Ignore:
Timestamp:
04/16/06 19:45:21 (8 years ago)
Author:
xi
Message:

Refactor resolver.

File:
1 moved

Legend:

Unmodified
Added
Removed
  • pyyaml/trunk/lib/yaml/resolver.py

    r136 r137  
    11 
    2 __all__ = ['BaseDetector', 'Detector'] 
     2__all__ = ['BaseResolver', 'Resolver'] 
     3 
     4from error import * 
     5from nodes import * 
    36 
    47import re 
    58 
    6 class BaseDetector: 
     9class ResolverError(YAMLError): 
     10    pass 
     11 
     12class BaseResolver: 
    713 
    814    DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str' 
     
    1016    DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map' 
    1117 
    12     yaml_detectors = {} 
     18    yaml_implicit_resolvers = {} 
     19    yaml_path_resolvers = {} 
    1320 
    1421    def __init__(self): 
    15         pass 
    16  
    17     def add_detector(cls, tag, regexp, first): 
    18         if not 'yaml_detectors' in cls.__dict__: 
    19             cls.yaml_detectors = cls.yaml_detectors.copy() 
     22        self.resolver_exact_paths = [] 
     23        self.resolver_prefix_paths = [] 
     24 
     25    def add_implicit_resolver(cls, tag, regexp, first): 
     26        if not 'yaml_implicit_resolvers' in cls.__dict__: 
     27            cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy() 
    2028        for ch in first: 
    21             cls.yaml_detectors.setdefault(ch, []).append((tag, regexp)) 
    22     add_detector = classmethod(add_detector) 
    23  
    24     def detect(self, value): 
    25         if value == u'': 
    26             detectors = self.yaml_detectors.get(u'', []) 
     29            cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp)) 
     30    add_implicit_resolver = classmethod(add_implicit_resolver) 
     31 
     32    def add_path_resolver(cls, tag, path, kind=None): 
     33        if not 'yaml_path_resolvers' in cls.__dict__: 
     34            cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy() 
     35        new_path = [] 
     36        for element in path: 
     37            if isinstance(element, (list, tuple)): 
     38                if len(element) == 2: 
     39                    node_check, index_check = element 
     40                elif len(element) == 1: 
     41                    node_check = element[0] 
     42                    index_check = True 
     43                else: 
     44                    raise ResolverError("Invalid path element: %s" % element) 
     45            else: 
     46                node_check = None 
     47                index_check = element 
     48            if node_check is str: 
     49                node_check = ScalarNode 
     50            elif node_check is list: 
     51                node_check = SequenceNode 
     52            elif node_check is map: 
     53                node_check = MappingNode 
     54            elif node_check not in [ScalarNode, SequenceNode, MappingNode]  \ 
     55                    and not isinstance(node_check, basestring)  \ 
     56                    and node_check is not None: 
     57                raise ResolverError("Invalid node checker: %s" % node_check) 
     58            if not isinstance(index_check, (basestring, int))   \ 
     59                    and index_check is not None: 
     60                raise ResolverError("Invalid index checker: %s" % index_check) 
     61            new_path.append((node_check, index_check)) 
     62        if kind is str: 
     63            kind = ScalarNode 
     64        elif kind is list: 
     65            kind = SequenceNode 
     66        elif kind is map: 
     67            kind = MappingNode 
     68        elif kind not in [ScalarNode, SequenceNode, MappingNode]    \ 
     69                and kind is not None: 
     70            raise ResolverError("Invalid node kind: %s" % kind) 
     71        cls.yaml_path_resolvers[tuple(new_path), kind] = tag 
     72    add_path_resolver = classmethod(add_path_resolver) 
     73 
     74    def descend_resolver(self, current_node, current_index): 
     75        exact_paths = {} 
     76        prefix_paths = [] 
     77        if current_node: 
     78            depth = len(self.resolver_prefix_paths) 
     79            for path, kind in self.resolver_prefix_paths[-1]: 
     80                if self.check_resolver_prefix(depth, path, kind, 
     81                        current_node, current_index): 
     82                    if len(path) > depth: 
     83                        prefix_paths.append((path, kind)) 
     84                    else: 
     85                        exact_paths[kind] = self.yaml_path_resolvers[path, kind] 
    2786        else: 
    28             detectors = self.yaml_detectors.get(value[0], []) 
    29         detectors += self.yaml_detectors.get(None, []) 
    30         for tag, regexp in detectors: 
    31             if regexp.match(value): 
    32                 return tag 
    33  
    34 class Detector(BaseDetector): 
     87            for path, kind in self.yaml_path_resolvers: 
     88                if not path: 
     89                    exact_paths[kind] = self.yaml_path_resolvers[path, kind] 
     90                else: 
     91                    prefix_paths.append((path, kind)) 
     92        self.resolver_exact_paths.append(exact_paths) 
     93        self.resolver_prefix_paths.append(prefix_paths) 
     94 
     95    def ascend_resolver(self): 
     96        self.resolver_exact_paths.pop() 
     97        self.resolver_prefix_paths.pop() 
     98 
     99    def check_resolver_prefix(self, depth, path, kind, 
     100            current_node, current_index): 
     101        node_check, index_check = path[depth-1] 
     102        if isinstance(node_check, basestring): 
     103            if current_node.tag != node_check: 
     104                return 
     105        elif node_check is not None: 
     106            if not isinstance(current_node, node_check): 
     107                return 
     108        if index_check is True and current_index is not None: 
     109            return 
     110        if index_check in [False, None] and current_index is None: 
     111            return 
     112        if isinstance(index_check, basestring): 
     113            if not (isinstance(current_index, ScalarNode) 
     114                    and index_check == current_index.value): 
     115                return 
     116        elif isinstance(index_check, int): 
     117            if index_check != current_index: 
     118                return 
     119        return True 
     120 
     121    def resolve(self, kind, value, implicit): 
     122        if kind is ScalarNode and implicit[0]: 
     123            if value == u'': 
     124                resolvers = self.yaml_implicit_resolvers.get(u'', []) 
     125            else: 
     126                resolvers = self.yaml_implicit_resolvers.get(value[0], []) 
     127            resolvers += self.yaml_implicit_resolvers.get(None, []) 
     128            for tag, regexp in resolvers: 
     129                if regexp.match(value): 
     130                    return tag 
     131            implicit = implicit[1] 
     132        exact_paths = self.resolver_exact_paths[-1] 
     133        if kind in exact_paths: 
     134            return exact_paths[kind] 
     135        if None in exact_paths: 
     136            return exact_paths[None] 
     137        if kind is ScalarNode: 
     138            return self.DEFAULT_SCALAR_TAG 
     139        elif kind is SequenceNode: 
     140            return self.DEFAULT_SEQUENCE_TAG 
     141        elif kind is MappingNode: 
     142            return self.DEFAULT_MAPPING_TAG 
     143 
     144class Resolver(BaseResolver): 
    35145    pass 
    36146 
    37 Detector.add_detector( 
     147Resolver.add_implicit_resolver( 
    38148        u'tag:yaml.org,2002:bool', 
    39149        re.compile(ur'''^(?:yes|Yes|YES|n|N|no|No|NO 
     
    42152        list(u'yYnNtTfFoO')) 
    43153 
    44 Detector.add_detector( 
     154Resolver.add_implicit_resolver( 
    45155        u'tag:yaml.org,2002:float', 
    46156        re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*(?:[eE][-+][0-9]+)? 
     
    50160        list(u'-+0123456789.')) 
    51161 
    52 Detector.add_detector( 
     162Resolver.add_implicit_resolver( 
    53163        u'tag:yaml.org,2002:int', 
    54164        re.compile(ur'''^(?:[-+]?0b[0-1_]+ 
     
    59169        list(u'-+0123456789')) 
    60170 
    61 Detector.add_detector( 
     171Resolver.add_implicit_resolver( 
    62172        u'tag:yaml.org,2002:merge', 
    63173        re.compile(ur'^(?:<<)$'), 
    64174        ['<']) 
    65175 
    66 Detector.add_detector( 
     176Resolver.add_implicit_resolver( 
    67177        u'tag:yaml.org,2002:null', 
    68178        re.compile(ur'''^(?: ~ 
     
    71181        [u'~', u'n', u'N', u'']) 
    72182 
    73 Detector.add_detector( 
     183Resolver.add_implicit_resolver( 
    74184        u'tag:yaml.org,2002:timestamp', 
    75185        re.compile(ur'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] 
     
    80190        list(u'0123456789')) 
    81191 
    82 Detector.add_detector( 
     192Resolver.add_implicit_resolver( 
    83193        u'tag:yaml.org,2002:value', 
    84194        re.compile(ur'^(?:=)$'), 
    85195        ['=']) 
    86196 
    87 # The following detector is only for documentation purposes. It cannot work 
     197# The following resolver is only for documentation purposes. It cannot work 
    88198# because plain scalars cannot start with '!', '&', or '*'. 
    89 Detector.add_detector( 
     199Resolver.add_implicit_resolver( 
    90200        u'tag:yaml.org,2002:yaml', 
    91201        re.compile(ur'^(?:!|&|\*)$'), 
Note: See TracChangeset for help on using the changeset viewer.