protostar 0.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +60 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +647 -0
  5. data/THIRD_PARTY_NOTICES.md +61 -0
  6. data/exe/protoc-gen-protostar +7 -0
  7. data/exe/protostar +7 -0
  8. data/lib/protostar/builder/generator.rb +71 -0
  9. data/lib/protostar/builder/sink.rb +35 -0
  10. data/lib/protostar/builder.rb +965 -0
  11. data/lib/protostar/cli.rb +267 -0
  12. data/lib/protostar/codec/decode_generator.rb +199 -0
  13. data/lib/protostar/codec/decoder.rb +296 -0
  14. data/lib/protostar/codec/encode_generator.rb +224 -0
  15. data/lib/protostar/codec/encoder.rb +121 -0
  16. data/lib/protostar/codec/sizer.rb +91 -0
  17. data/lib/protostar/codec.rb +15 -0
  18. data/lib/protostar/compiler/ast.rb +193 -0
  19. data/lib/protostar/compiler/emitters/descriptor_set.rb +57 -0
  20. data/lib/protostar/compiler/emitters/google_ruby.rb +103 -0
  21. data/lib/protostar/compiler/emitters/grpc.rb +175 -0
  22. data/lib/protostar/compiler/emitters/protostar_rbs.rb +252 -0
  23. data/lib/protostar/compiler/emitters/rbs.rb +394 -0
  24. data/lib/protostar/compiler/emitters/ruby.rb +503 -0
  25. data/lib/protostar/compiler/emitters.rb +268 -0
  26. data/lib/protostar/compiler/include/LICENSE +32 -0
  27. data/lib/protostar/compiler/include/google/protobuf/any.proto +106 -0
  28. data/lib/protostar/compiler/include/google/protobuf/api.proto +229 -0
  29. data/lib/protostar/compiler/include/google/protobuf/compiler/plugin.proto +180 -0
  30. data/lib/protostar/compiler/include/google/protobuf/cpp_features.proto +87 -0
  31. data/lib/protostar/compiler/include/google/protobuf/descriptor.proto +1532 -0
  32. data/lib/protostar/compiler/include/google/protobuf/duration.proto +115 -0
  33. data/lib/protostar/compiler/include/google/protobuf/empty.proto +51 -0
  34. data/lib/protostar/compiler/include/google/protobuf/field_mask.proto +243 -0
  35. data/lib/protostar/compiler/include/google/protobuf/java_features.proto +132 -0
  36. data/lib/protostar/compiler/include/google/protobuf/source_context.proto +48 -0
  37. data/lib/protostar/compiler/include/google/protobuf/struct.proto +111 -0
  38. data/lib/protostar/compiler/include/google/protobuf/timestamp.proto +145 -0
  39. data/lib/protostar/compiler/include/google/protobuf/type.proto +217 -0
  40. data/lib/protostar/compiler/include/google/protobuf/wrappers.proto +157 -0
  41. data/lib/protostar/compiler/lexer.rb +659 -0
  42. data/lib/protostar/compiler/linker.rb +894 -0
  43. data/lib/protostar/compiler/option_interpreter.rb +363 -0
  44. data/lib/protostar/compiler/parser.rb +1696 -0
  45. data/lib/protostar/compiler/retention.rb +104 -0
  46. data/lib/protostar/compiler/run.rb +184 -0
  47. data/lib/protostar/compiler/source_info.rb +161 -0
  48. data/lib/protostar/compiler/symbol_table.rb +223 -0
  49. data/lib/protostar/compiler/text_format.rb +340 -0
  50. data/lib/protostar/compiler/validator.rb +944 -0
  51. data/lib/protostar/compiler.rb +304 -0
  52. data/lib/protostar/diagnostics/codes.rb +1307 -0
  53. data/lib/protostar/diagnostics/formats.rb +64 -0
  54. data/lib/protostar/diagnostics/renderer.rb +240 -0
  55. data/lib/protostar/diagnostics/source.rb +153 -0
  56. data/lib/protostar/diagnostics.rb +117 -0
  57. data/lib/protostar/dsl.rb +367 -0
  58. data/lib/protostar/enum.rb +70 -0
  59. data/lib/protostar/errors.rb +23 -0
  60. data/lib/protostar/google/protobuf/any_pb.rb +90 -0
  61. data/lib/protostar/google/protobuf/api_pb.rb +199 -0
  62. data/lib/protostar/google/protobuf/compiler/plugin_pb.rb +168 -0
  63. data/lib/protostar/google/protobuf/descriptor_pb.rb +1239 -0
  64. data/lib/protostar/google/protobuf/duration_pb.rb +99 -0
  65. data/lib/protostar/google/protobuf/empty_pb.rb +36 -0
  66. data/lib/protostar/google/protobuf/field_mask_pb.rb +228 -0
  67. data/lib/protostar/google/protobuf/source_context_pb.rb +33 -0
  68. data/lib/protostar/google/protobuf/struct_pb.rb +91 -0
  69. data/lib/protostar/google/protobuf/timestamp_pb.rb +129 -0
  70. data/lib/protostar/google/protobuf/type_pb.rb +202 -0
  71. data/lib/protostar/google/protobuf/wrappers_pb.rb +125 -0
  72. data/lib/protostar/google_protobuf_shim.rb +24 -0
  73. data/lib/protostar/json/encoder.rb +340 -0
  74. data/lib/protostar/json/errors.rb +34 -0
  75. data/lib/protostar/json/parser.rb +437 -0
  76. data/lib/protostar/json/path.rb +39 -0
  77. data/lib/protostar/json.rb +95 -0
  78. data/lib/protostar/lint/command.rb +197 -0
  79. data/lib/protostar/lint/config.rb +98 -0
  80. data/lib/protostar/lint/context.rb +126 -0
  81. data/lib/protostar/lint/directives.rb +56 -0
  82. data/lib/protostar/lint/fixer.rb +165 -0
  83. data/lib/protostar/lint/naming.rb +54 -0
  84. data/lib/protostar/lint/rule.rb +120 -0
  85. data/lib/protostar/lint/rules/comment_enum.rb +31 -0
  86. data/lib/protostar/lint/rules/comment_enum_value.rb +32 -0
  87. data/lib/protostar/lint/rules/comment_field.rb +33 -0
  88. data/lib/protostar/lint/rules/comment_message.rb +31 -0
  89. data/lib/protostar/lint/rules/comment_rpc.rb +31 -0
  90. data/lib/protostar/lint/rules/comment_service.rb +31 -0
  91. data/lib/protostar/lint/rules/edition_recommended.rb +31 -0
  92. data/lib/protostar/lint/rules/enum_first_value_zero.rb +34 -0
  93. data/lib/protostar/lint/rules/enum_pascal_case.rb +25 -0
  94. data/lib/protostar/lint/rules/enum_value_prefix.rb +38 -0
  95. data/lib/protostar/lint/rules/enum_value_upper_snake_case.rb +28 -0
  96. data/lib/protostar/lint/rules/enum_zero_value_suffix.rb +41 -0
  97. data/lib/protostar/lint/rules/field_lower_snake_case.rb +34 -0
  98. data/lib/protostar/lint/rules/field_not_required.rb +39 -0
  99. data/lib/protostar/lint/rules/field_number_reuse_risk.rb +45 -0
  100. data/lib/protostar/lint/rules/field_numbers_hot_range.rb +44 -0
  101. data/lib/protostar/lint/rules/file_lower_snake_case.rb +27 -0
  102. data/lib/protostar/lint/rules/import_no_public.rb +29 -0
  103. data/lib/protostar/lint/rules/import_no_weak.rb +28 -0
  104. data/lib/protostar/lint/rules/import_used.rb +33 -0
  105. data/lib/protostar/lint/rules/message_pascal_case.rb +27 -0
  106. data/lib/protostar/lint/rules/no_deprecated_features.rb +50 -0
  107. data/lib/protostar/lint/rules/no_groups.rb +34 -0
  108. data/lib/protostar/lint/rules/oneof_lower_snake_case.rb +27 -0
  109. data/lib/protostar/lint/rules/package_defined.rb +28 -0
  110. data/lib/protostar/lint/rules/package_directory_match.rb +33 -0
  111. data/lib/protostar/lint/rules/package_lower_snake_case.rb +28 -0
  112. data/lib/protostar/lint/rules/package_same_directory.rb +39 -0
  113. data/lib/protostar/lint/rules/package_version_suffix.rb +31 -0
  114. data/lib/protostar/lint/rules/reserved_names_with_numbers.rb +44 -0
  115. data/lib/protostar/lint/rules/rpc_pascal_case.rb +25 -0
  116. data/lib/protostar/lint/rules/rpc_request_response_unique.rb +40 -0
  117. data/lib/protostar/lint/rules/rpc_request_standard_name.rb +32 -0
  118. data/lib/protostar/lint/rules/rpc_response_standard_name.rb +31 -0
  119. data/lib/protostar/lint/rules/service_pascal_case.rb +25 -0
  120. data/lib/protostar/lint/rules/service_suffix.rb +28 -0
  121. data/lib/protostar/lint/rules/syntax_specified.rb +35 -0
  122. data/lib/protostar/lint/runner.rb +135 -0
  123. data/lib/protostar/lint.rb +122 -0
  124. data/lib/protostar/message/accessors.rb +86 -0
  125. data/lib/protostar/message/coercion.rb +171 -0
  126. data/lib/protostar/message/field_info.rb +145 -0
  127. data/lib/protostar/message/reflection.rb +149 -0
  128. data/lib/protostar/message.rb +572 -0
  129. data/lib/protostar/plugin.rb +94 -0
  130. data/lib/protostar/schema/default_value.rb +113 -0
  131. data/lib/protostar/schema/descriptor.rb +41 -0
  132. data/lib/protostar/schema/draft/copy.rb +88 -0
  133. data/lib/protostar/schema/draft/resolution.rb +177 -0
  134. data/lib/protostar/schema/draft.rb +779 -0
  135. data/lib/protostar/schema/enum.rb +106 -0
  136. data/lib/protostar/schema/extension_range.rb +37 -0
  137. data/lib/protostar/schema/features.rb +153 -0
  138. data/lib/protostar/schema/field.rb +201 -0
  139. data/lib/protostar/schema/file.rb +217 -0
  140. data/lib/protostar/schema/freezer.rb +61 -0
  141. data/lib/protostar/schema/message.rb +104 -0
  142. data/lib/protostar/schema/oneof.rb +38 -0
  143. data/lib/protostar/schema/options.rb +367 -0
  144. data/lib/protostar/schema/pool.rb +179 -0
  145. data/lib/protostar/schema/proto.rb +576 -0
  146. data/lib/protostar/schema/resolver.rb +118 -0
  147. data/lib/protostar/schema/service.rb +89 -0
  148. data/lib/protostar/schema/source_info.rb +53 -0
  149. data/lib/protostar/schema.rb +65 -0
  150. data/lib/protostar/short_names/any.rb +7 -0
  151. data/lib/protostar/short_names/duration.rb +7 -0
  152. data/lib/protostar/short_names/empty.rb +7 -0
  153. data/lib/protostar/short_names/field_mask.rb +7 -0
  154. data/lib/protostar/short_names/struct.rb +9 -0
  155. data/lib/protostar/short_names/timestamp.rb +7 -0
  156. data/lib/protostar/short_names/wrappers.rb +15 -0
  157. data/lib/protostar/text/extensions.rb +114 -0
  158. data/lib/protostar/text/parser.rb +439 -0
  159. data/lib/protostar/text/printer.rb +304 -0
  160. data/lib/protostar/text/tokenizer.rb +116 -0
  161. data/lib/protostar/text.rb +67 -0
  162. data/lib/protostar/types.rb +152 -0
  163. data/lib/protostar/unknown_field.rb +58 -0
  164. data/lib/protostar/version.rb +5 -0
  165. data/lib/protostar/view/generator.rb +298 -0
  166. data/lib/protostar/view/map.rb +194 -0
  167. data/lib/protostar/view/repeated.rb +143 -0
  168. data/lib/protostar/view/scan.rb +183 -0
  169. data/lib/protostar/view.rb +283 -0
  170. data/lib/protostar/well_known/any.rb +52 -0
  171. data/lib/protostar/well_known/duration.rb +53 -0
  172. data/lib/protostar/well_known/list_value.rb +63 -0
  173. data/lib/protostar/well_known/struct.rb +55 -0
  174. data/lib/protostar/well_known/timestamp.rb +64 -0
  175. data/lib/protostar/well_known/value.rb +60 -0
  176. data/lib/protostar/well_known.rb +38 -0
  177. data/lib/protostar/wire/io_source.rb +40 -0
  178. data/lib/protostar/wire/reader.rb +254 -0
  179. data/lib/protostar/wire/writer.rb +201 -0
  180. data/lib/protostar/wire.rb +96 -0
  181. data/lib/protostar.rb +95 -0
  182. data/shims/google-protobuf/lib/google/protobuf/any_pb.rb +17 -0
  183. data/shims/google-protobuf/lib/google/protobuf/api_pb.rb +22 -0
  184. data/shims/google-protobuf/lib/google/protobuf/compiler/plugin_pb.rb +25 -0
  185. data/shims/google-protobuf/lib/google/protobuf/descriptor_pb.rb +72 -0
  186. data/shims/google-protobuf/lib/google/protobuf/descriptor_pool.rb +164 -0
  187. data/shims/google-protobuf/lib/google/protobuf/descriptors.rb +553 -0
  188. data/shims/google-protobuf/lib/google/protobuf/duration_pb.rb +17 -0
  189. data/shims/google-protobuf/lib/google/protobuf/empty_pb.rb +17 -0
  190. data/shims/google-protobuf/lib/google/protobuf/field_mask_pb.rb +17 -0
  191. data/shims/google-protobuf/lib/google/protobuf/internal/convert.rb +180 -0
  192. data/shims/google-protobuf/lib/google/protobuf/internal/extensions.rb +154 -0
  193. data/shims/google-protobuf/lib/google/protobuf/internal/json.rb +104 -0
  194. data/shims/google-protobuf/lib/google/protobuf/internal/well_known.rb +140 -0
  195. data/shims/google-protobuf/lib/google/protobuf/map.rb +216 -0
  196. data/shims/google-protobuf/lib/google/protobuf/message.rb +544 -0
  197. data/shims/google-protobuf/lib/google/protobuf/message_exts.rb +41 -0
  198. data/shims/google-protobuf/lib/google/protobuf/plugin_pb.rb +4 -0
  199. data/shims/google-protobuf/lib/google/protobuf/repeated_field.rb +366 -0
  200. data/shims/google-protobuf/lib/google/protobuf/source_context_pb.rb +17 -0
  201. data/shims/google-protobuf/lib/google/protobuf/struct_pb.rb +20 -0
  202. data/shims/google-protobuf/lib/google/protobuf/timestamp_pb.rb +17 -0
  203. data/shims/google-protobuf/lib/google/protobuf/type_pb.rb +27 -0
  204. data/shims/google-protobuf/lib/google/protobuf/well_known_types.rb +37 -0
  205. data/shims/google-protobuf/lib/google/protobuf/wrappers_pb.rb +25 -0
  206. data/shims/google-protobuf/lib/google/protobuf.rb +107 -0
  207. data/shims/google-protobuf/lib/google/protobuf_ffi.rb +5 -0
  208. data/shims/google-protobuf/lib/google/protobuf_native.rb +5 -0
  209. data/sig/protostar/google/protobuf/any_pb.rbs +77 -0
  210. data/sig/protostar/google/protobuf/api_pb.rbs +242 -0
  211. data/sig/protostar/google/protobuf/compiler/plugin_pb.rbs +264 -0
  212. data/sig/protostar/google/protobuf/descriptor_pb.rbs +2220 -0
  213. data/sig/protostar/google/protobuf/duration_pb.rbs +82 -0
  214. data/sig/protostar/google/protobuf/empty_pb.rbs +18 -0
  215. data/sig/protostar/google/protobuf/field_mask_pb.rbs +170 -0
  216. data/sig/protostar/google/protobuf/source_context_pb.rbs +24 -0
  217. data/sig/protostar/google/protobuf/struct_pb.rbs +135 -0
  218. data/sig/protostar/google/protobuf/timestamp_pb.rbs +102 -0
  219. data/sig/protostar/google/protobuf/type_pb.rbs +304 -0
  220. data/sig/protostar/google/protobuf/wrappers_pb.rbs +169 -0
  221. data/sig/protostar/lint.rbs +216 -0
  222. data/sig/protostar.rbs +326 -0
  223. metadata +366 -0
@@ -0,0 +1,340 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ class Compiler
5
+ # Just enough of protoc's text-format parser to read aggregate option
6
+ # values (`option (opt) = { a: 1 b { c: "x" } [ext]: 2 };`) into option
7
+ # entries, with protoc's error messages for the common mistakes.
8
+ #
9
+ # @api private
10
+ class TextFormat
11
+ ANY_PREFIXES = ["type.googleapis.com/", "type.googleprod.com/"].freeze
12
+ INT32_MAX = 2**31 - 1
13
+ INT64_MAX = 2**63 - 1
14
+ UINT32_MAX = 2**32 - 1
15
+ UINT64_MAX = 2**64 - 1
16
+ RECURSION_LIMIT = 100
17
+
18
+ # @return [Array<String>]
19
+ attr_reader :errors
20
+
21
+ # @param text [String] the aggregate value, braces excluded
22
+ # @param type [Schema::Message]
23
+ # @param interpreter [OptionInterpreter] maps symbols to descriptors
24
+ # @param table [SymbolTable] resolves `[extension]` names
25
+ def initialize(text, type, interpreter, table)
26
+ @type = type
27
+ @interpreter = interpreter
28
+ @table = table
29
+ @errors = []
30
+ @lexer = Lexer.new(text, ->(_line, _column, message) { @errors << message })
31
+ @lexer.next
32
+ @depth = RECURSION_LIMIT
33
+ end
34
+
35
+ # @return [Array, nil] the entries, or nil after errors
36
+ def parse
37
+ entries = []
38
+ until looking_at_type?(:end)
39
+ return nil unless consume_field(@type, entries)
40
+ end
41
+ @errors.empty? ? entries : nil
42
+ end
43
+
44
+ private
45
+
46
+ def looking_at?(text)
47
+ @lexer.current.text == text
48
+ end
49
+
50
+ def looking_at_type?(type)
51
+ @lexer.current.type == type
52
+ end
53
+
54
+ def try_consume(text)
55
+ return false unless looking_at?(text)
56
+ @lexer.next
57
+ true
58
+ end
59
+
60
+ def consume(text)
61
+ return true if try_consume(text)
62
+ error("Expected \"#{text}\", found \"#{@lexer.current.text}\".")
63
+ end
64
+
65
+ def error(message)
66
+ @errors << message
67
+ false
68
+ end
69
+
70
+ def consume_message(type, delimiter, entries)
71
+ @depth -= 1
72
+ return error("Message is too deep, the parser exceeded the configured recursion limit of #{RECURSION_LIMIT}.") if @depth < 0
73
+ until looking_at?(">") || looking_at?("}")
74
+ return false unless consume_field(type, entries)
75
+ end
76
+ consume(delimiter)
77
+ ensure
78
+ @depth += 1
79
+ end
80
+
81
+ def message_delimiter
82
+ return ">" if try_consume("<")
83
+ consume("{") ? "}" : nil
84
+ end
85
+
86
+ # The text between brackets, URL characters included
87
+ def bracketed_name
88
+ consume("[")
89
+ name = +""
90
+ until looking_at?("]") || looking_at_type?(:end)
91
+ name << @lexer.current.text
92
+ @lexer.next
93
+ end
94
+ return nil unless consume("]")
95
+ name
96
+ end
97
+
98
+ def consume_field(type, entries)
99
+ if type.full_name == "google.protobuf.Any" && looking_at?("[")
100
+ return consume_any(type, entries)
101
+ end
102
+
103
+ if looking_at?("[")
104
+ name = bracketed_name
105
+ return false unless name
106
+ return error("Extension name contains \"/\"") if name.include?("/")
107
+ field = find_extension(type, name)
108
+ unless field
109
+ return error("Extension \"#{name}\" is not defined or is not an extension of \"#{type.full_name}\".")
110
+ end
111
+ else
112
+ unless looking_at_type?(:identifier)
113
+ return error("Expected identifier, got: #{@lexer.current.text}")
114
+ end
115
+ name = @lexer.current.text.dup.force_encoding(Encoding::UTF_8)
116
+ @lexer.next
117
+ field = type.fields_by_name[name]
118
+ if field.nil?
119
+ lower = type.fields_by_name[name.downcase]
120
+ field = lower if lower && group_like?(lower) && lower.message_type.name == name
121
+ end
122
+ return error("Message type \"#{type.full_name}\" has no field named \"#{name}\".") unless field
123
+ end
124
+
125
+ if !field.repeated? && entries.any? { |f, _| f.equal?(field) }
126
+ return error("Non-repeated field \"#{name}\" is specified multiple times.")
127
+ end
128
+ if (oneof = field.real_oneof) && (other = entries.find { |f, _| f.real_oneof.equal?(oneof) })
129
+ return error("Field \"#{name}\" is specified along with field \"#{other[0].name}\", another member of " \
130
+ "oneof \"#{oneof.name}\".")
131
+ end
132
+
133
+ message = field.type == :message || field.type == :group
134
+ if message
135
+ try_consume(":")
136
+ else
137
+ return false unless consume(":")
138
+ end
139
+
140
+ if field.repeated? && try_consume("[")
141
+ unless try_consume("]")
142
+ loop do
143
+ value = message ? field_message(field) : field_value(field)
144
+ return false if value.nil?
145
+ entries << [field, value]
146
+ break if try_consume("]")
147
+ return false unless consume(",")
148
+ end
149
+ end
150
+ else
151
+ value = message ? field_message(field) : field_value(field)
152
+ return false if value.nil?
153
+ entries << [field, value]
154
+ end
155
+ try_consume(";") || try_consume(",")
156
+ true
157
+ end
158
+
159
+ def group_like?(field)
160
+ return false unless field.type == :group
161
+ return false unless field.name == field.message_type.name.downcase
162
+ return false unless field.message_type.file.equal?(field.file)
163
+ field.message_type.containing_message.equal?(field.containing_message)
164
+ end
165
+
166
+ def find_extension(type, name)
167
+ symbol = @table.lookup(name, type.full_name)
168
+ if symbol&.kind == :field
169
+ field = @interpreter.schema_of(symbol)
170
+ return field if field.extension? && field.extendee.full_name == type.full_name
171
+ return nil
172
+ end
173
+ if symbol&.kind == :message && type.message_set_wire_format?
174
+ foreign = @interpreter.schema_of(symbol)
175
+ return foreign.extensions.find do |ext|
176
+ ext.extendee.full_name == type.full_name && ext.type == :message && ext.label == :optional &&
177
+ ext.message_type.equal?(foreign)
178
+ end
179
+ end
180
+ nil
181
+ end
182
+
183
+ def field_message(field)
184
+ delimiter = message_delimiter
185
+ return nil unless delimiter
186
+ entries = []
187
+ return nil unless consume_message(field.message_type, delimiter, entries)
188
+ entries
189
+ end
190
+
191
+ def consume_any(type, entries)
192
+ text = bracketed_name
193
+ return false unless text
194
+ slash = text.rindex("/")
195
+ return error("Type URL prefix is missing") unless slash
196
+ prefix = text[0..slash]
197
+ full_name = text[(slash + 1)..]
198
+ try_consume(":")
199
+ target = nil
200
+ if ANY_PREFIXES.include?(prefix)
201
+ symbol = @table.find(full_name)
202
+ target = @interpreter.schema_of(symbol) if symbol&.kind == :message
203
+ end
204
+ return error("Could not find type \"#{text}\" stored in google.protobuf.Any.") unless target
205
+ delimiter = message_delimiter
206
+ return false unless delimiter
207
+ inner = []
208
+ return false unless consume_message(target, delimiter, inner)
209
+ if entries.any? { |f, _| f.number == 1 || f.number == 2 }
210
+ return error("Non-repeated Any specified multiple times.")
211
+ end
212
+ entries << [type.field(1), text]
213
+ entries << [type.field(2), @interpreter.fold(inner).encode(target)]
214
+ try_consume(";") || try_consume(",")
215
+ true
216
+ end
217
+
218
+ def field_value(field)
219
+ case field.type
220
+ when :int32, :sint32, :sfixed32 then signed_integer(INT32_MAX)
221
+ when :int64, :sint64, :sfixed64 then signed_integer(INT64_MAX)
222
+ when :uint32, :fixed32 then unsigned_integer(UINT32_MAX)
223
+ when :uint64, :fixed64 then unsigned_integer(UINT64_MAX)
224
+ when :float
225
+ v = double
226
+ v.nil? ? nil : Schema::DefaultValue.to_float32(v)
227
+ when :double then double
228
+ when :string, :bytes
229
+ unless looking_at_type?(:string)
230
+ error("Expected string, got: #{@lexer.current.text}")
231
+ return nil
232
+ end
233
+ out = "".b
234
+ while looking_at_type?(:string)
235
+ Lexer.parse_string(@lexer.current.text, out)
236
+ @lexer.next
237
+ end
238
+ (field.type == :string) ? out.force_encoding(Encoding::UTF_8) : out
239
+ when :bool
240
+ if looking_at_type?(:integer)
241
+ v = unsigned_integer(1)
242
+ return v.nil? ? nil : v == 1
243
+ end
244
+ unless looking_at_type?(:identifier)
245
+ error("Expected identifier, got: #{@lexer.current.text}")
246
+ return nil
247
+ end
248
+ text = @lexer.current.text
249
+ @lexer.next
250
+ case text
251
+ when "true", "True", "t" then true
252
+ when "false", "False", "f" then false
253
+ else
254
+ error("Invalid value for boolean field \"#{field.name}\". Value: \"#{text}\".")
255
+ nil
256
+ end
257
+ when :enum then enum_value(field)
258
+ end
259
+ end
260
+
261
+ def enum_value(field)
262
+ enum = field.enum_type
263
+ if looking_at_type?(:identifier)
264
+ text = @lexer.current.text
265
+ @lexer.next
266
+ value = enum.values_by_name[text]
267
+ elsif looking_at?("-") || looking_at_type?(:integer)
268
+ number = signed_integer(INT32_MAX)
269
+ return nil if number.nil?
270
+ text = number.to_s
271
+ value = enum.value(number)
272
+ return number if value.nil? && !enum.closed?
273
+ else
274
+ error("Expected integer or identifier, got: #{@lexer.current.text}")
275
+ return nil
276
+ end
277
+ unless value
278
+ error("Unknown enumeration value of \"#{text}\" for field \"#{field.name}\".")
279
+ return nil
280
+ end
281
+ enum.values_by_number.fetch(value.number).name.to_sym
282
+ end
283
+
284
+ def unsigned_integer(max)
285
+ unless looking_at_type?(:integer)
286
+ error("Expected integer, got: #{@lexer.current.text}")
287
+ return nil
288
+ end
289
+ value = Lexer.parse_integer(@lexer.current.text, max)
290
+ unless value
291
+ error("Integer out of range (#{@lexer.current.text})")
292
+ return nil
293
+ end
294
+ @lexer.next
295
+ value
296
+ end
297
+
298
+ def signed_integer(max)
299
+ negative = try_consume("-")
300
+ value = unsigned_integer(negative ? max + 1 : max)
301
+ return nil if value.nil?
302
+ negative ? -value : value
303
+ end
304
+
305
+ def double
306
+ negative = try_consume("-")
307
+ token = @lexer.current
308
+ value = case token.type
309
+ when :integer
310
+ if token.text.match?(/\A0[xX]/) || token.text.match?(/\A0\d/)
311
+ error("Expect a decimal number, got: #{token.text}")
312
+ return nil
313
+ end
314
+ int = Lexer.parse_integer(token.text, UINT64_MAX)
315
+ @lexer.next
316
+ int ? int.to_f : Lexer.parse_float(token.text)
317
+ when :float
318
+ @lexer.next
319
+ Lexer.parse_float(token.text)
320
+ when :identifier
321
+ text = token.text.downcase
322
+ if text == "inf" || text == "infinity"
323
+ @lexer.next
324
+ Float::INFINITY
325
+ elsif text == "nan"
326
+ @lexer.next
327
+ Float::NAN
328
+ else
329
+ error("Expected double, got: #{text}")
330
+ return nil
331
+ end
332
+ else
333
+ error("Expected double, got: #{token.text}")
334
+ return nil
335
+ end
336
+ negative ? -value : value
337
+ end
338
+ end
339
+ end
340
+ end