v

Зеркало из https://github.com/vlang/v
Форк
0
/x
/
strict.v 
186 строк · 3.9 Кб
1
module strict
2

3
import arrays
4

5
pub struct KeyStruct {
6
pub:
7
	key        string
8
	value_type KeyType
9
	token_pos  int // the position of the token
10
}
11

12
pub enum KeyType {
13
	literal
14
	map
15
	array
16
}
17

18
pub struct StructCheckResult {
19
pub:
20
	duplicates  []string
21
	superfluous []string
22
}
23

24
// strict_check
25
pub fn strict_check[T](json_data string) StructCheckResult {
26
	// REVIEW how performatic is it?
27
	$if T is $struct {
28
		tokens := tokenize(json_data)
29

30
		key_struct := get_keys_from_json(tokens)
31

32
		mut duplicates := get_duplicates_keys(key_struct)
33
		mut superfluous := get_superfluous_keys[T](key_struct)
34

35
		mut val := T{}
36

37
		$for field in T.fields {
38
			$if field.typ is $struct {
39
				field_name := field.name
40
				last_key := arrays.find_last(key_struct, fn [field_name] (k KeyStruct) bool {
41
					return k.key == field_name
42
				}) or { panic('${field.name} not found') }
43

44
				// TODO: get path here from `last_key.key`
45
				if last_key.value_type == .map {
46
					check(val.$(field.name), tokens[last_key.token_pos + 2..], mut duplicates, mut
47
						superfluous)
48
				}
49
			}
50
		}
51
		return StructCheckResult{
52
			duplicates:  duplicates
53
			superfluous: superfluous
54
		}
55
	} $else {
56
		return StructCheckResult{}
57
	}
58
}
59

60
fn check[T](val T, tokens []string, mut duplicates []string, mut superfluous []string) {
61
	$if T is $struct {
62
		key_struct := get_keys_from_json(tokens)
63

64
		for duplicate in get_duplicates_keys(key_struct) {
65
			duplicates << duplicate
66
		}
67

68
		for unnecessary in get_superfluous_keys[T](key_struct) {
69
			superfluous << unnecessary
70
		}
71

72
		$for field in T.fields {
73
			$if field.typ is $struct {
74
				if last_key.value_type == .map {
75
					check(val.$(field.name), tokens[last_key.token_pos + 2..], mut duplicates, mut
76
						superfluous)
77
				}
78
			}
79
		}
80
	}
81
}
82

83
fn get_superfluous_keys[T](key_struct []KeyStruct) []string {
84
	mut superfluous := []string{}
85

86
	struct_keys := get_keys_from_[T]()
87

88
	json_keys := key_struct.map(fn (json_key KeyStruct) string {
89
		return json_key.key
90
	})
91

92
	for json_key in json_keys {
93
		if !struct_keys.contains(json_key) {
94
			superfluous << json_key
95
		}
96
	}
97
	return superfluous
98
}
99

100
fn get_duplicates_keys(key_struct []KeyStruct) []string {
101
	json_keys := key_struct.map(it.key).sorted()
102
	return arrays.uniq_only_repeated(json_keys)
103
}
104

105
fn get_keys_from_[T]() []string {
106
	mut struct_keys := []string{}
107
	$if T is $struct {
108
		$for field in T.fields {
109
			struct_keys << field.name
110
		}
111
	}
112
	return struct_keys
113
}
114

115
// get_keys_from_json
116
pub fn get_keys_from_json(tokens []string) []KeyStruct {
117
	mut key_structs := []KeyStruct{}
118

119
	mut nested_map_count := 0
120

121
	for i, token in tokens {
122
		if token == ':' {
123
			mut current_key := tokens[i - 1].replace('"', '')
124
			if tokens[i + 1] == '{' {
125
				if nested_map_count == 0 {
126
					key_type := KeyType.map
127
					key_structs << KeyStruct{
128
						key:        current_key
129
						value_type: key_type
130
						token_pos:  i - 1
131
					}
132
				}
133
				nested_map_count++
134
			} else if tokens[i + 1] == '[' {
135
				continue
136
			} else if nested_map_count > 0 {
137
				if tokens[i + 1] == '}' {
138
					nested_map_count--
139
				} else {
140
					// REVIEW Não sei
141
				}
142
			} else {
143
				key_type := KeyType.literal
144
				key_structs << KeyStruct{
145
					key:        current_key
146
					value_type: key_type
147
					token_pos:  i - 1
148
				}
149
			}
150
		}
151
	}
152

153
	return key_structs
154
}
155

156
fn tokenize(json_data string) []string {
157
	mut tokens := []string{}
158
	mut current_token := ''
159
	mut inside_string := false
160

161
	for letter in json_data.replace('\n', ' ').replace('\t', ' ') {
162
		if letter == ` ` && !inside_string {
163
			if current_token != '' {
164
				tokens << current_token
165
				current_token = ''
166
			}
167
		} else if letter == `\"` {
168
			inside_string = !inside_string
169
			current_token += '"'
170
		} else if letter == `,` || letter == `:` || letter == `{` || letter == `}` || letter == `[`
171
			|| letter == `]` {
172
			if current_token != '' {
173
				tokens << current_token
174
				current_token = ''
175
			}
176
			tokens << [letter].bytestr()
177
		} else {
178
			current_token += [letter].bytestr()
179
		}
180
	}
181

182
	if current_token != '' {
183
		tokens << current_token
184
	}
185
	return tokens
186
}
187

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.