Changeset 47


Ignore:
Timestamp:
02/17/06 17:39:52 (8 years ago)
Author:
xi
Message:

Working on the scanner.

Location:
branches/pyyaml3000
Files:
6 added
9 edited
2 copied

Legend:

Unmodified
Added
Removed
  • branches/pyyaml3000/lib/yaml/parser.py

    r46 r47  
    9696    def parse_stream(self): 
    9797        documents = [] 
    98         if not self.is_token(DirectiveToken, DocumentStartToken, EndToken): 
     98        if not self.is_token(DirectiveToken, DocumentStartToken, StreamEndToken): 
    9999            documents.append(self.parse_block_node()) 
    100         while not self.is_token(EndToken): 
     100        while not self.is_token(StreamEndToken): 
    101101            while self.is_token(DirectiveToken): 
    102102                self.get_token() 
     
    105105            self.get_token() 
    106106            if self.is_token(DirectiveToken, 
    107                     DocumentStartToken, DocumentEndToken, EndToken): 
     107                    DocumentStartToken, DocumentEndToken, StreamEndToken): 
    108108                documents.append(None) 
    109109            else: 
     
    111111            while self.is_token(DocumentEndToken): 
    112112                self.get_token() 
    113         if not self.is_token(EndToken): 
    114             self.fail("END is expected") 
     113        if not self.is_token(StreamEndToken): 
     114            self.fail("STREAM-END is expected") 
    115115        return documents 
    116116 
     
    285285    def fail(self, message): 
    286286        marker = self.scanner.peek_token().start_marker 
    287         raise Error(message+':\n'+marker.get_snippet()) 
    288  
     287        raise ParserError(message+':\n'+marker.get_snippet()) 
     288 
  • branches/pyyaml3000/lib/yaml/reader.py

    r46 r47  
    6666        self.pointer = pointer 
    6767 
    68     def get_snippet(self, max_length=79): 
     68    def get_snippet(self, indent=4, max_length=75): 
    6969        if self.buffer is None: 
    7070            return None 
     
    8686                break 
    8787        snippet = self.buffer[start:end].encode('utf-8') 
    88         return head + snippet + tail + '\n'  \ 
    89                 + ' '*(self.pointer-start+len(head)) + '^' + '\n' 
     88        return ' '*indent + head + snippet + tail + '\n'  \ 
     89                + ' '*(indent+self.pointer-start+len(head)) + '^' 
     90 
     91    def __str__(self): 
     92        snippet = self.get_snippet() 
     93        where = "  in \"%s\", line %d, column %d"   \ 
     94                % (self.name, self.line+1, self.column+1) 
     95        if snippet is not None: 
     96            where += ":\n"+snippet 
     97        return where 
    9098 
    9199class ReaderError(YAMLError): 
     
    101109        if isinstance(self.character, str): 
    102110            return "'%s' codec can't decode byte #x%02x: %s\n"  \ 
    103                     "\tin '%s', position %d."   \ 
     111                    "  in \"%s\", position %d"    \ 
    104112                    % (self.encoding, ord(self.character), self.reason, 
    105113                            self.name, self.position) 
    106114        else: 
    107115            return "unacceptable character #x%04x: %s\n"    \ 
    108                     "\tin '%s', position %d."   \ 
     116                    "  in \"%s\", position %d"    \ 
    109117                    % (ord(self.character), self.reason, 
    110118                            self.name, self.position) 
  • branches/pyyaml3000/lib/yaml/scanner.py

    r46 r47  
    2424    # key: "valu\?e" 
    2525    #            ^ 
    26     pass 
     26    def __init__(self, context=None, context_marker=None, 
     27            problem=None, problem_marker=None, description=None): 
     28        self.context = context 
     29        self.context_marker = context_marker 
     30        self.problem = problem 
     31        self.problem_marker = problem_marker 
     32        self.description = description 
     33 
     34    def __str__(self): 
     35        lines = [] 
     36        for (place, marker) in [(self.context, self.context_marker), 
     37                                (self.problem, self.problem_marker)]: 
     38            if place is not None: 
     39                lines.append(place) 
     40                if marker is not None: 
     41                    lines.append(str(marker)) 
     42        if self.description is not None: 
     43            lines.append(self.description) 
     44        return '\n'.join(lines) 
    2745 
    2846class SimpleKey: 
     
    140158        # and decrease the current indentation level. 
    141159        self.unwind_indent(self.reader.column) 
    142  
    143         #print 
    144         #print self.reader.get_marker().get_snippet() 
    145160 
    146161        # Peek the next character. 
     
    257272                    or self.reader.index-key.index > 1024: 
    258273                if key.required: 
    259                     self.fail("simple key is required") 
     274                    raise ScannerError("while scanning a simple key", key.marker, 
     275                            "could not found expected ':'", self.reader.get_marker()) 
    260276                del self.possible_simple_keys[level] 
    261277 
     
    267283        # Check if a simple key is required at the current position. 
    268284        required = not self.flow_level and self.indent == self.reader.column 
     285 
     286        # A simple key is required only if it is the first token in the current 
     287        # line. Therefore it is always allowed. 
     288        assert self.allow_simple_key or not required 
    269289 
    270290        # The next token might be a simple key. Let's save it's number and 
     
    281301            self.possible_simple_keys[self.flow_level] = key 
    282302 
    283         # A simple key is required at the current position. 
    284         elif required: 
    285             self.fail("simple key is required") 
    286  
    287303    def remove_possible_simple_key(self): 
    288304        # Remove the saved possible key position at the current flow level. 
    289305        if self.flow_level in self.possible_simple_keys: 
    290306            key = self.possible_simple_keys[self.flow_level] 
    291             if key.required: 
    292                 self.fail("simple key is required") 
     307             
     308            # I don't think it's possible, but I could be wrong. 
     309            assert not key.required 
     310            #if key.required: 
     311            #    raise ScannerError("while scanning a simple key", key.marker, 
     312            #            "could not found expected ':'", self.reader.get_marker()) 
    293313 
    294314    # Indentation functions. 
     
    297317 
    298318        # In flow context, tokens should respect indentation. 
     319        # Actually the condition should be `self.indent >= column` according to 
     320        # the spec. But this condition will prohibit intuitively correct 
     321        # constructions such as 
     322        # key : { 
     323        # } 
    299324        if self.flow_level and self.indent > column: 
    300             self.fail("invalid intendation in the flow context") 
     325            raise ScannerError(None, None, 
     326                    "invalid intendation or unclosed '[' or '{'", 
     327                    self.reader.get_marker()) 
    301328 
    302329        # In block context, we may need to issue the BLOCK-END tokens. 
     
    329356         
    330357        # Add END. 
    331         self.tokens.append(EndToken(marker, marker)) 
     358        self.tokens.append(StreamEndToken(marker, marker)) 
    332359 
    333360        # The reader is ended. 
     
    344371 
    345372        # Scan and add DIRECTIVE. 
    346         self.scan_directive() 
     373        self.tokens.append(self.scan_directive()) 
    347374 
    348375    def fetch_document_start(self): 
     
    421448            # Are we allowed to start a new entry? 
    422449            if not self.allow_simple_key: 
    423                 self.fail("Cannot start a new entry here") 
     450                raise ScannerError(None, None, 
     451                        "sequence entries are not allowed here", 
     452                        self.reader.get_marker()) 
    424453 
    425454            # We may need to add BLOCK-SEQUENCE-START. 
     
    447476            # Are we allowed to start a key (not nessesary a simple)? 
    448477            if not self.allow_simple_key: 
    449                 self.fail("Cannot start a new key here") 
     478                raise ScannerError(None, None, 
     479                        "mapping keys are not allowed here", 
     480                        self.reader.get_marker()) 
    450481 
    451482            # We may need to add BLOCK-MAPPING-START. 
     
    490521        else: 
    491522             
     523            # Block context needs additional checks. 
     524            # (Do we really need them? They will be catched by the parser 
     525            # anyway.) 
     526            if not self.flow_level: 
     527 
     528                # We are allowed to start a complex value if and only if 
     529                # we can start a simple key. 
     530                if not self.allow_simple_key: 
     531                    raise ScannerError(None, None, 
     532                            "mapping values are not allowed here", 
     533                            self.reader.get_marker()) 
     534 
    492535            # Simple keys are allowed after ':' in the block context. 
    493536            self.allow_simple_key = not self.flow_level 
     
    511554 
    512555        # Scan and add ALIAS. 
    513         self.scan_anchor(AliasToken) 
     556        self.tokens.append(self.scan_anchor(AliasToken)) 
    514557 
    515558    def fetch_anchor(self): 
     
    522565 
    523566        # Scan and add ANCHOR. 
    524         self.scan_anchor(AnchorToken) 
     567        self.tokens.append(self.scan_anchor(AnchorToken)) 
    525568 
    526569    def fetch_tag(self): 
     
    533576 
    534577        # Scan and add TAG. 
    535         self.scan_tag() 
     578        self.tokens.append(self.scan_tag()) 
    536579 
    537580    def fetch_literal(self): 
     
    550593 
    551594        # Scan and add SCALAR. 
    552         self.scan_block_scalar(folded) 
     595        self.tokens.append(self.scan_block_scalar(folded)) 
    553596 
    554597    def fetch_single(self): 
     
    567610 
    568611        # Scan and add SCALAR. 
    569         self.scan_flow_scalar(double) 
     612        self.tokens.append(self.scan_flow_scalar(double)) 
    570613 
    571614    def fetch_plain(self): 
     
    580623 
    581624        # Scan and add SCALAR. May change `allow_simple_key`. 
    582         self.scan_plain() 
     625        self.tokens.append(self.scan_plain()) 
    583626 
    584627    # Checkers. 
     
    646689 
    647690    def scan_to_next_token(self): 
     691        # We ignore spaces, line breaks and comments. 
     692        # If we find a line break in the block context, we set the flag 
     693        # `allow_simple_key` on. 
    648694        found = False 
    649695        while not found: 
     
    651697                self.reader.forward() 
    652698            if self.reader.peek() == u'#': 
    653                 while self.reader.peek() not in u'\r\n': 
     699                while self.reader.peek() not in u'\0\r\n\x85\u2028\u2029': 
    654700                    self.reader.forward() 
    655             if self.reader.peek() in u'\r\n': 
    656                 self.reader.forward() 
     701            if self.scan_line_break(): 
    657702                if not self.flow_level: 
    658703                    self.allow_simple_key = True 
     
    663708        marker = self.reader.get_marker() 
    664709        if self.reader.peek(5) == u'%YAML ': 
    665             self.tokens.append(YAMLDirectiveToken(1, 1, marker, marker)) 
     710            token = YAMLDirectiveToken(1, 1, marker, marker) 
    666711        elif self.reader.peek(4) == u'%TAG ': 
    667             self.tokens.append(TagDirectiveToken(marker, marker)) 
     712            token = TagDirectiveToken(marker, marker) 
    668713        else: 
    669             self.tokens.append(ReservedDirectiveToken('', marker, marker)) 
     714            token = ReservedDirectiveToken('', marker, marker) 
    670715        while self.reader.peek() not in u'\0\r\n': 
    671716            self.reader.forward() 
    672717        self.reader.forward() 
     718        return token 
    673719 
    674720    def scan_anchor(self, TokenClass): 
     
    677723            self.reader.forward() 
    678724        end_marker = self.reader.get_marker() 
    679         self.tokens.append(TokenClass('', start_marker, end_marker)) 
     725        return TokenClass('', start_marker, end_marker) 
    680726 
    681727    def scan_tag(self): 
     
    684730            self.reader.forward() 
    685731        end_marker = self.reader.get_marker() 
    686         self.tokens.append(TagToken('', start_marker, end_marker)) 
     732        return TagToken('', start_marker, end_marker) 
    687733 
    688734    def scan_block_scalar(self, folded): 
     
    702748            if count < indent and self.reader.peek() not in u'#\r\n\x85\u2028\u2029': 
    703749                break 
    704         self.tokens.append(ScalarToken('', False, start_marker, start_marker)) 
     750        return ScalarToken('', False, start_marker, start_marker) 
    705751 
    706752    def scan_flow_scalar(self, double): 
     
    716762                self.reader.forward(1) 
    717763        self.reader.forward(1) 
    718         self.tokens.append(ScalarToken('', False, marker, marker)) 
     764        return ScalarToken('', False, marker, marker) 
    719765 
    720766    def scan_plain(self): 
     
    748794                break 
    749795            space = True 
    750         self.tokens.append(ScalarToken('', True, marker, marker)) 
     796        return ScalarToken('', True, marker, marker) 
     797 
     798    def scan_line_break(self): 
     799        # Transforms: 
     800        #   '\r\n'      :   '\n' 
     801        #   '\r'        :   '\n' 
     802        #   '\n'        :   '\n' 
     803        #   '\x85'      :   '\n' 
     804        #   '\u2028'    :   '\u2028' 
     805        #   '\u2029     :   '\u2029' 
     806        #   default     :   '' 
     807        ch = self.reader.peek() 
     808        if ch in u'\r\n\x85': 
     809            if self.reader.peek(2) == u'\r\n': 
     810                self.forward(2) 
     811            else: 
     812                self.reader.forward() 
     813            return u'\n' 
     814        elif ch in u'\u2028\u2029': 
     815            self.reader.forward() 
     816            return ch 
     817        return u'' 
    751818 
    752819    def invalid_token(self): 
    753820        self.fail("invalid token") 
    754  
    755     def fail(self, message): 
    756         raise ScannerError(message) 
    757821 
    758822#try: 
  • branches/pyyaml3000/lib/yaml/tokens.py

    r46 r47  
    66 
    77class DirectiveToken(Token): 
    8     pass 
     8    code = '<directive>' 
    99 
    1010class YAMLDirectiveToken(DirectiveToken): 
     11    code = '<%YAML directive>' 
    1112    def __init__(self, major_version, minor_version, start_marker, end_marker): 
    1213        self.major_version = major_version 
     
    1617 
    1718class TagDirectiveToken(DirectiveToken): 
    18     pass 
     19    code = '<%TAG directive>' 
    1920 
    2021class ReservedDirectiveToken(DirectiveToken): 
     22    code = '<unknown directive>' 
    2123    def __init__(self, name, start_marker, end_marker): 
    2224        self.name = name 
     
    2527 
    2628class DocumentStartToken(Token): 
    27     pass 
     29    code = '<document start>' 
    2830 
    2931class DocumentEndToken(Token): 
    30     pass 
     32    code = '<document end>' 
    3133 
    32 class EndToken(Token): 
    33     pass 
     34class StreamEndToken(Token): 
     35    code = '<stream end>' 
    3436 
    3537class BlockSequenceStartToken(Token): 
    36     pass 
     38    code = '<block sequence start>' 
    3739 
    3840class BlockMappingStartToken(Token): 
    39     pass 
     41    code = '<block mapping end>' 
    4042 
    4143class BlockEndToken(Token): 
    42     pass 
     44    code = '<block end>' 
    4345 
    4446class FlowSequenceStartToken(Token): 
    45     pass 
     47    code = '[' 
    4648 
    4749class FlowMappingStartToken(Token): 
    48     pass 
     50    code = '{' 
    4951 
    5052class FlowSequenceEndToken(Token): 
    51     pass 
     53    code = ']' 
    5254 
    5355class FlowMappingEndToken(Token): 
    54     pass 
     56    code = '}' 
    5557 
    5658class KeyToken(Token): 
    57     pass 
     59    code = '?' 
    5860 
    5961class ValueToken(Token): 
    60     pass 
     62    code = ':' 
    6163 
    6264class EntryToken(Token): 
    63     pass 
     65    code = '- or ,' 
    6466 
    6567class AliasToken(Token): 
     68    code = '<alias>' 
    6669    def __init__(self, value, start_marker, end_marker): 
    6770        self.value = value 
     
    7073 
    7174class AnchorToken(Token): 
     75    code = '<anchor>' 
    7276    def __init__(self, value, start_marker, end_marker): 
    7377        self.value = value 
     
    7680 
    7781class TagToken(Token): 
     82    code = '<tag>' 
    7883    def __init__(self, value, start_marker, end_marker): 
    7984        self.value = value 
     
    8287 
    8388class ScalarToken(Token): 
     89    code = '<scalar>' 
    8490    def __init__(self, value, plain, start_marker, end_marker): 
    8591        self.value = value 
  • branches/pyyaml3000/tests/data/spec-10-07.data

    r44 r47  
    11{ 
    2 #? : value # Empty key 
    3 ? ~ : value, # Empty key 
     2? : value, # Empty key 
    43? explicit 
    54 key: value, 
  • branches/pyyaml3000/tests/test_appliance.py

    r45 r47  
    7070        return "%s(%s)" % (self.__class__.__name__, ''.join(args)) 
    7171 
    72 class EndToken(Token): 
     72class StreamEndToken(Token): 
    7373    pass 
    7474 
     
    133133            ch = self.data[self.index] 
    134134            if ch == u'\0': 
    135                 tokens.append(EndToken()) 
     135                tokens.append(StreamEndToken()) 
    136136                break 
    137137            elif ch == u'%': 
     
    286286    def parse_stream(self): 
    287287        documents = [] 
    288         while not self.test_token(EndToken): 
     288        while not self.test_token(StreamEndToken): 
    289289            if self.test_token(DirectiveToken, DocumentStartToken): 
    290290                documents.append(self.parse_document()) 
  • branches/pyyaml3000/tests/test_marker.py

    r46 r47  
    2020                index += 1 
    2121            marker = Marker(test_name, line, column, unicode(input), index) 
    22             snippet = marker.get_snippet() 
     22            snippet = marker.get_snippet(indent=2, max_length=79) 
    2323            #print "INPUT:" 
    2424            #print input 
     
    2626            #print snippet 
    2727            self.failUnless(isinstance(snippet, str)) 
    28             self.failUnlessEqual(snippet.count('\n'), 2) 
    29             data, pointer, dummy = snippet.split('\n') 
    30             self.failUnless(len(data) < 80) 
     28            self.failUnlessEqual(snippet.count('\n'), 1) 
     29            data, pointer = snippet.split('\n') 
     30            self.failUnless(len(data) < 82) 
    3131            self.failUnlessEqual(data[len(pointer)-1], '*') 
    3232 
  • branches/pyyaml3000/tests/test_tokens.py

    r46 r47  
    5555            scanner = Scanner(Reader(file(data_filename, 'rb'))) 
    5656            tokens1 = [] 
    57             while not isinstance(scanner.peek_token(), EndToken): 
     57            while not isinstance(scanner.peek_token(), StreamEndToken): 
    5858                tokens1.append(scanner.get_token()) 
    5959            tokens1 = [self.replaces[t.__class__] for t in tokens1] 
     
    7777                scanner = Scanner(Reader(file(filename, 'rb'))) 
    7878                tokens = [] 
    79                 while not isinstance(scanner.peek_token(), EndToken): 
     79                while not isinstance(scanner.peek_token(), StreamEndToken): 
    8080                    tokens.append(scanner.get_token().__class__.__name__) 
    8181            except: 
  • branches/pyyaml3000/tests/test_yaml.py

    r46 r47  
    77from test_tokens import * 
    88from test_structure import * 
     9from test_errors import * 
    910 
    1011def main(module='__main__'): 
Note: See TracChangeset for help on using the changeset viewer.