summaryrefslogtreecommitdiffstats
path: root/powerline/lint/markedjson/resolver.py
blob: fa8ceaa4b4b0bdddf9d531c9635174a5699ad0a9 (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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

import re

from powerline.lint.markedjson.error import MarkedError
from powerline.lint.markedjson import nodes


class ResolverError(MarkedError):
	pass


class BaseResolver:
	DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str'
	DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq'
	DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map'

	yaml_implicit_resolvers = {}
	yaml_path_resolvers = {}

	def __init__(self):
		self.resolver_exact_paths = []
		self.resolver_prefix_paths = []

	@classmethod
	def add_implicit_resolver(cls, tag, regexp, first):
		if 'yaml_implicit_resolvers' not in cls.__dict__:
			cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy()
		if first is None:
			first = [None]
		for ch in first:
			cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))

	def descend_resolver(self, current_node, current_index):
		if not self.yaml_path_resolvers:
			return
		exact_paths = {}
		prefix_paths = []
		if current_node:
			depth = len(self.resolver_prefix_paths)
			for path, kind in self.resolver_prefix_paths[-1]:
				if self.check_resolver_prefix(depth, path, kind, current_node, current_index):
					if len(path) > depth:
						prefix_paths.append((path, kind))
					else:
						exact_paths[kind] = self.yaml_path_resolvers[path, kind]
		else:
			for path, kind in self.yaml_path_resolvers:
				if not path:
					exact_paths[kind] = self.yaml_path_resolvers[path, kind]
				else:
					prefix_paths.append((path, kind))
		self.resolver_exact_paths.append(exact_paths)
		self.resolver_prefix_paths.append(prefix_paths)

	def ascend_resolver(self):
		if not self.yaml_path_resolvers:
			return
		self.resolver_exact_paths.pop()
		self.resolver_prefix_paths.pop()

	def check_resolver_prefix(self, depth, path, kind, current_node, current_index):
		node_check, index_check = path[depth - 1]
		if isinstance(node_check, str):
			if current_node.tag != node_check:
				return
		elif node_check is not None:
			if not isinstance(current_node, node_check):
				return
		if index_check is True and current_index is not None:
			return
		if ((index_check is False or index_check is None)
			and current_index is None):
			return
		if isinstance(index_check, str):
			if not (isinstance(current_index, nodes.ScalarNode) and index_check == current_index.value):
				return
		elif isinstance(index_check, int) and not isinstance(index_check, bool):
			if index_check != current_index:
				return
		return True

	def resolve(self, kind, value, implicit, mark=None):
		if kind is nodes.ScalarNode and implicit[0]:
			if value == '':
				resolvers = self.yaml_implicit_resolvers.get('', [])
			else:
				resolvers = self.yaml_implicit_resolvers.get(value[0], [])
			resolvers += self.yaml_implicit_resolvers.get(None, [])
			for tag, regexp in resolvers:
				if regexp.match(value):
					return tag
			else:
				self.echoerr(
					'While resolving plain scalar', None,
					'expected floating-point value, integer, null or boolean, but got %r' % value,
					mark
				)
				return self.DEFAULT_SCALAR_TAG
		if kind is nodes.ScalarNode:
			return self.DEFAULT_SCALAR_TAG
		elif kind is nodes.SequenceNode:
			return self.DEFAULT_SEQUENCE_TAG
		elif kind is nodes.MappingNode:
			return self.DEFAULT_MAPPING_TAG


class Resolver(BaseResolver):
	pass


Resolver.add_implicit_resolver(
	'tag:yaml.org,2002:bool',
	re.compile(r'''^(?:true|false)$''', re.X),
	list('yYnNtTfFoO'))

Resolver.add_implicit_resolver(
	'tag:yaml.org,2002:float',
	re.compile(r'^-?(?:0|[1-9]\d*)(?=[.eE])(?:\.\d+)?(?:[eE][-+]?\d+)?$', re.X),
	list('-0123456789'))

Resolver.add_implicit_resolver(
	'tag:yaml.org,2002:int',
	re.compile(r'^(?:0|-?[1-9]\d*)$', re.X),
	list('-0123456789'))

Resolver.add_implicit_resolver(
	'tag:yaml.org,2002:null',
	re.compile(r'^null$', re.X),
	['n'])