bare-rb 0.1.2 → 0.2.0
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.
- checksums.yaml +4 -4
- data/lib/bare-rb.rb +52 -10
- data/lib/exceptions.rb +30 -0
- data/lib/generative_testing/gen.rb +26 -0
- data/lib/generative_testing/grammar_util.rb +22 -0
- data/lib/generative_testing/monkey_patch.rb +262 -0
- data/lib/lexer.rb +17 -16
- data/lib/parser.rb +66 -18
- data/lib/types.rb +544 -254
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbfb767287130c73249bf016a4bc3b4d9b6bd44e82ce8e7d9e3557ee6c58e7b3
|
4
|
+
data.tar.gz: aee2d8ab8457356c7e544dbd31c6f81d05c9655ab3138ddfe7315ab221d16ea0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1d6c44757bcdd9f6811bf0107e7b13d68703e6616faef2029b09f2273ae75168eff02091f13cddfd6c5e5b9499db5efe2d7cf72d88c3c0e001a0da00b4c602f
|
7
|
+
data.tar.gz: e38a97985800775f0aa995db17ad9b8ea6a1294e12f0e0fd5cc60008359d286af6ec173bad63d190436bbd0bea876ff590e0a1fcac6099bd394ce9790bac1798
|
data/lib/bare-rb.rb
CHANGED
@@ -2,22 +2,65 @@ require 'set'
|
|
2
2
|
require_relative "types"
|
3
3
|
require_relative "lexer"
|
4
4
|
require_relative "parser"
|
5
|
+
require_relative 'dfs'
|
6
|
+
require_relative 'generative_testing/gen'
|
7
|
+
require_relative 'generative_testing/monkey_patch'
|
5
8
|
|
6
9
|
class Bare
|
10
|
+
def self.encode(msg, schema, type = nil)
|
11
|
+
buffer = "".b
|
12
|
+
if schema.is_a?(BareTypes::Schema)
|
13
|
+
raise NoTypeProvided.new("To encode with a schema as opposed to a raw type you must specify which type in the schema you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
|
14
|
+
unless schema.types.include?(type)
|
15
|
+
raise("#{type} is not a type found in this schema. Choose from #{schema.types.keys}")
|
16
|
+
end
|
17
|
+
schema[type].encode(msg, buffer)
|
18
|
+
else
|
19
|
+
schema.encode(msg, buffer)
|
20
|
+
end
|
21
|
+
buffer
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.decode(msg, schema, type = nil)
|
25
|
+
if schema.is_a?(BareTypes::Schema)
|
26
|
+
raise NoTypeProvided.new("To decode with a schema as opposed to a raw type you must specify which type in the same you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
|
27
|
+
value, _ = schema[type].decode(msg)
|
28
|
+
value
|
29
|
+
else
|
30
|
+
value, _ = schema.decode(msg)
|
31
|
+
value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a schema and a binary input
|
36
|
+
# optionally write these to files
|
37
|
+
def self.generative_test(schema_path=nil, binary_path=nil)
|
38
|
+
schema = BareTypes::Schema.make
|
39
|
+
input = schema.create_input
|
40
|
+
key = schema.types.keys[0]
|
41
|
+
binary = Bare.encode(input[key], schema, key)
|
42
|
+
unless binary_path.nil?
|
43
|
+
file = File.open(binary_path, 'wb+')
|
44
|
+
file.write(binary)
|
45
|
+
file.close
|
46
|
+
end
|
47
|
+
unless schema_path.nil?
|
48
|
+
file = File.open(schema_path, 'w+')
|
49
|
+
file.write(schema.to_s)
|
50
|
+
file.close
|
51
|
+
end
|
52
|
+
return schema, binary, key
|
53
|
+
end
|
7
54
|
|
8
55
|
def self.parse_schema(path)
|
9
|
-
# Hash of class names to BARE
|
56
|
+
# Hash of class names to BARE types
|
10
57
|
# Eg. types['Customer'] == Bare.i32
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.encode(msg, schema)
|
16
|
-
return schema.encode(msg)
|
58
|
+
parsed = parser(lexer(path))
|
59
|
+
Bare.Schema(parsed)
|
17
60
|
end
|
18
61
|
|
19
|
-
def self.
|
20
|
-
|
62
|
+
def self.Schema(hash)
|
63
|
+
BareTypes::Schema.new(hash)
|
21
64
|
end
|
22
65
|
|
23
66
|
# These classes are wrapped in methods for ergonomics.
|
@@ -119,4 +162,3 @@ class Bare
|
|
119
162
|
return BareTypes::Enum.new(*opts)
|
120
163
|
end
|
121
164
|
end
|
122
|
-
|
data/lib/exceptions.rb
CHANGED
@@ -5,6 +5,36 @@ class BareException < StandardError
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
class InvalidBool < BareException
|
9
|
+
def initialize(msg = nil)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class CircularSchema < BareException
|
15
|
+
def initialize(msg = nil)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class ReferenceException < BareException
|
21
|
+
def initialize(msg=nil)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class FixedDataSizeWrong < BareException
|
27
|
+
def initialize(msg=nil)
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class NoTypeProvided < BareException
|
33
|
+
def initialize(msg = nil)
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
8
38
|
class SchemaParsingException < BareException
|
9
39
|
def initialize(msg=nil)
|
10
40
|
super
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../bare-rb'
|
2
|
+
require_relative './monkey_patch'
|
3
|
+
require_relative './grammar_util'
|
4
|
+
|
5
|
+
def get_type(depth, names = [], can_be_symbol = true)
|
6
|
+
if names.size == 0
|
7
|
+
can_be_symbol = false
|
8
|
+
end
|
9
|
+
terminators = [BareTypes::Data, BareTypes::DataFixedLen,
|
10
|
+
BareTypes::U8, BareTypes::U16, BareTypes::U32, BareTypes::U64,
|
11
|
+
BareTypes::I8, BareTypes::I16, BareTypes::I32, BareTypes::I64,
|
12
|
+
BareTypes::F32, BareTypes::F64]
|
13
|
+
aggregates = [BareTypes::Array, BareTypes::ArrayFixedLen,
|
14
|
+
BareTypes::Struct]
|
15
|
+
|
16
|
+
all = terminators + aggregates
|
17
|
+
|
18
|
+
# 1/5 changes of a reference
|
19
|
+
if rand(5) == 0 && names.size != 1 && can_be_symbol
|
20
|
+
names[rand(names.size)]
|
21
|
+
elsif depth >= 10 # if depth >= 10 only use terminating types
|
22
|
+
all[rand(terminators.size)].make(depth + 1, names)
|
23
|
+
else
|
24
|
+
all[rand(all.size)].make(depth + 1, names)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
def create_user_type_name
|
2
|
+
upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
3
|
+
lower = upper.downcase
|
4
|
+
digit = "0123456789"
|
5
|
+
|
6
|
+
name = upper[rand(upper.size)]
|
7
|
+
loop do
|
8
|
+
if rand(50) < 5
|
9
|
+
break
|
10
|
+
end
|
11
|
+
num = rand(3)
|
12
|
+
if num == 0
|
13
|
+
name << upper[rand(upper.size)]
|
14
|
+
elsif num == 1
|
15
|
+
name << lower[rand(lower.size)]
|
16
|
+
else
|
17
|
+
name << digit[rand(digit.size)]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
name.to_sym
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,262 @@
|
|
1
|
+
require_relative '../bare-rb'
|
2
|
+
require_relative './grammar_util'
|
3
|
+
|
4
|
+
# 10MB max data size
|
5
|
+
DATA_MAX_SIZE = 30000
|
6
|
+
ARRAY_MAX_SIZE = 40
|
7
|
+
STRUCT_FIELDS_MAX = 5
|
8
|
+
|
9
|
+
# Monkey patch every bare class to include make and create_input
|
10
|
+
# make - a factory to create a random variant of the bare class
|
11
|
+
# create_input - creates an input that could be used with Bare.Encode for this type
|
12
|
+
|
13
|
+
class BareTypes::Reference
|
14
|
+
def create_input
|
15
|
+
self.ref.create_input
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.make(depth, names)
|
19
|
+
self.ref.make(depth, names)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# region Integers
|
24
|
+
class BareTypes::U8
|
25
|
+
def self.make(depth, names)
|
26
|
+
BareTypes::U8.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_input
|
30
|
+
rand(256)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class BareTypes::U16
|
35
|
+
def self.make(depth, names)
|
36
|
+
BareTypes::U16.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_input
|
40
|
+
rand(2 ** 16)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class BareTypes::U32
|
45
|
+
def self.make(depth, names)
|
46
|
+
BareTypes::U32.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_input
|
50
|
+
rand(2 ** 32)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class BareTypes::U64
|
55
|
+
def self.make(depth, names)
|
56
|
+
BareTypes::U64.new
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_input
|
60
|
+
rand(2 ** 64)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class BareTypes::I8
|
65
|
+
def self.make(depth, names)
|
66
|
+
BareTypes::I8.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_input
|
70
|
+
rand(2 ** 8) - (2 ** 7)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class BareTypes::I16
|
75
|
+
def self.make(depth, names)
|
76
|
+
BareTypes::I16.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_input
|
80
|
+
rand(2 ** 16) - (2 ** 15)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class BareTypes::I32
|
85
|
+
def self.make(depth, names)
|
86
|
+
BareTypes::I32.new
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_input
|
90
|
+
rand(2 ** 32) - (2 ** 31)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class BareTypes::I64
|
95
|
+
def self.make(depth, names)
|
96
|
+
BareTypes::I64.new
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_input
|
100
|
+
rand(2 ** 64) - (2 ** 63)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# endregion
|
105
|
+
|
106
|
+
#region Floats
|
107
|
+
class BareTypes::F32
|
108
|
+
def self.make(depth, names)
|
109
|
+
self.new
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_input
|
113
|
+
float = nil
|
114
|
+
loop do
|
115
|
+
input = [rand(266), rand(266), rand(266), rand(266)]
|
116
|
+
float = input.pack("cccc").unpack('e')
|
117
|
+
if float[0] == float[0] && !float[0].nan?
|
118
|
+
break
|
119
|
+
end
|
120
|
+
end
|
121
|
+
float[0]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class BareTypes::F64
|
126
|
+
def self.make(depth, names)
|
127
|
+
self.new
|
128
|
+
end
|
129
|
+
|
130
|
+
def create_input
|
131
|
+
float = nil
|
132
|
+
loop do
|
133
|
+
input = [rand(266), rand(266), rand(266), rand(266), rand(266), rand(266), rand(266), rand(266)]
|
134
|
+
float = input.pack("cccccccc").unpack('E')
|
135
|
+
if float[0] == float[0] && !float[0].nan?
|
136
|
+
break
|
137
|
+
end
|
138
|
+
end
|
139
|
+
float[0]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
#endregion
|
144
|
+
|
145
|
+
#region Data
|
146
|
+
class BareTypes::DataFixedLen
|
147
|
+
def self.make(depth, names)
|
148
|
+
length = rand(max = DATA_MAX_SIZE) + 1
|
149
|
+
self.new(length)
|
150
|
+
end
|
151
|
+
|
152
|
+
def create_input
|
153
|
+
# 100 random bytes
|
154
|
+
arr = []
|
155
|
+
0.upto(length - 1).each do |i|
|
156
|
+
arr << i % 256
|
157
|
+
end
|
158
|
+
arr.pack('c*')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class BareTypes::Data
|
163
|
+
def self.make(depth, names)
|
164
|
+
self.new
|
165
|
+
end
|
166
|
+
|
167
|
+
def create_input
|
168
|
+
arr = []
|
169
|
+
0.upto(rand(DATA_MAX_SIZE)).each do |i|
|
170
|
+
arr << i % 256
|
171
|
+
end
|
172
|
+
arr.pack('c*')
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
#endregion
|
177
|
+
|
178
|
+
#region Array
|
179
|
+
class BareTypes::Array
|
180
|
+
def self.make(depth, names)
|
181
|
+
BareTypes::Array.new(get_type(depth + 1, names))
|
182
|
+
end
|
183
|
+
|
184
|
+
def create_input
|
185
|
+
count = rand(ARRAY_MAX_SIZE) + 1
|
186
|
+
arr = []
|
187
|
+
0.upto(count) do
|
188
|
+
arr << @type.create_input
|
189
|
+
end
|
190
|
+
arr
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class BareTypes::ArrayFixedLen
|
195
|
+
def self.make(depth, names)
|
196
|
+
self.new(get_type(depth + 1, names,), rand(ARRAY_MAX_SIZE) + 1)
|
197
|
+
end
|
198
|
+
|
199
|
+
def create_input
|
200
|
+
arr = []
|
201
|
+
0.upto(@size - 1) do
|
202
|
+
arr << @type.create_input
|
203
|
+
end
|
204
|
+
arr
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
#endregion
|
209
|
+
|
210
|
+
#region Agg Types
|
211
|
+
|
212
|
+
class BareTypes::Struct
|
213
|
+
def self.make(depth, names)
|
214
|
+
hash = {}
|
215
|
+
0.upto(rand(STRUCT_FIELDS_MAX) + 1) do
|
216
|
+
hash[create_user_type_name.to_sym] = get_type(depth + 1, names)
|
217
|
+
end
|
218
|
+
self.new(hash)
|
219
|
+
end
|
220
|
+
|
221
|
+
def create_input
|
222
|
+
input = {}
|
223
|
+
@mapping.keys.each do |name|
|
224
|
+
input[name] = @mapping[name].create_input
|
225
|
+
end
|
226
|
+
input
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# endregion
|
231
|
+
|
232
|
+
class BareTypes::Schema
|
233
|
+
def create_input
|
234
|
+
input = {}
|
235
|
+
@types.each do |key, type|
|
236
|
+
input[key] = type.create_input
|
237
|
+
end
|
238
|
+
input
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.make
|
242
|
+
schema = nil
|
243
|
+
loop do
|
244
|
+
names = []
|
245
|
+
schema = {}
|
246
|
+
0.upto(rand(10)+1) do
|
247
|
+
names << create_user_type_name.to_sym
|
248
|
+
end
|
249
|
+
names.each do |name|
|
250
|
+
without_this_name = names.select { |n| n != name }
|
251
|
+
schema[name] = get_type(0, without_this_name, false)
|
252
|
+
end
|
253
|
+
begin
|
254
|
+
schema = Bare.Schema(schema)
|
255
|
+
rescue CircularSchema
|
256
|
+
next
|
257
|
+
end
|
258
|
+
break
|
259
|
+
end
|
260
|
+
schema
|
261
|
+
end
|
262
|
+
end
|
data/lib/lexer.rb
CHANGED
@@ -3,55 +3,56 @@ require_relative './exceptions'
|
|
3
3
|
def lexer(path)
|
4
4
|
tokens = []
|
5
5
|
line_num = 0
|
6
|
-
File.open(path)
|
6
|
+
file = File.open(path)
|
7
|
+
file.each do |line|
|
7
8
|
while line.size > 0
|
8
9
|
if /^#/.match(line)
|
9
10
|
break
|
10
11
|
elsif /^\n/.match(line)
|
11
12
|
break
|
12
13
|
elsif /^ /.match(line)
|
13
|
-
line = line[1..]
|
14
|
+
line = line[1..line.size]
|
14
15
|
elsif /^</.match(line)
|
15
|
-
line = line[1..]
|
16
|
+
line = line[1..line.size]
|
16
17
|
tokens << :less_than
|
17
18
|
elsif /^>/.match(line)
|
18
|
-
line = line[1..]
|
19
|
+
line = line[1..line.size]
|
19
20
|
tokens << :greater_than
|
20
21
|
next
|
21
22
|
elsif /^{/.match(line)
|
22
|
-
line = line[1..]
|
23
|
+
line = line[1..line.size]
|
23
24
|
tokens << :open_block
|
24
25
|
elsif /^=/.match(line)
|
25
|
-
line = line[1..]
|
26
|
+
line = line[1..line.size]
|
26
27
|
tokens << :equal
|
27
28
|
elsif /^}/.match(line)
|
28
|
-
line = line[1..]
|
29
|
+
line = line[1..line.size]
|
29
30
|
tokens << :close_block
|
30
31
|
elsif /^\[/.match(line)
|
31
|
-
line = line[1..]
|
32
|
+
line = line[1..line.size]
|
32
33
|
tokens << :open_brace
|
33
34
|
elsif /^\]/.match(line)
|
34
|
-
line = line[1..]
|
35
|
+
line = line[1..line.size]
|
35
36
|
tokens << :close_brace
|
36
37
|
elsif /^\(/.match(line)
|
37
|
-
line = line[1..]
|
38
|
+
line = line[1..line.size]
|
38
39
|
tokens << :open_paren
|
39
40
|
elsif /^\)/.match(line)
|
40
|
-
line = line[1..]
|
41
|
+
line = line[1..line.size]
|
41
42
|
tokens << :close_paren
|
42
43
|
elsif /^\|/.match(line)
|
43
|
-
line = line[1..]
|
44
|
+
line = line[1..line.size]
|
44
45
|
tokens << :bar
|
45
46
|
elsif match = /^([0-9]+)/.match(line)
|
46
47
|
tokens << match[0].to_i
|
47
|
-
line = line[(match.size
|
48
|
+
line = line[(match[0].size)..line.size]
|
48
49
|
next
|
49
|
-
elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]
|
50
|
+
elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]*/.match(line)
|
50
51
|
tokens << match[0]
|
51
|
-
line = line[(match[0].size)..]
|
52
|
+
line = line[(match[0].size)..line.size]
|
52
53
|
elsif /:/.match(line)
|
53
54
|
tokens << :colon
|
54
|
-
line = line[1..]
|
55
|
+
line = line[1..line.size]
|
55
56
|
else
|
56
57
|
raise SchemaParsingException.new("Unable to lex line #{line_num} near #{line.inspect}")
|
57
58
|
end
|
data/lib/parser.rb
CHANGED
@@ -38,55 +38,103 @@ class Parser
|
|
38
38
|
name = tokens[0]
|
39
39
|
int_repr = tokens[2]
|
40
40
|
enum_hash[int_repr] = name
|
41
|
-
tokens = tokens[3..]
|
41
|
+
tokens = tokens[3..tokens.size]
|
42
42
|
else
|
43
43
|
enum_hash[count] = tokens[0]
|
44
44
|
count += 1
|
45
|
-
tokens = tokens[1..]
|
45
|
+
tokens = tokens[1..tokens.size]
|
46
46
|
end
|
47
47
|
end
|
48
48
|
enum = Bare.Enum(enum_hash)
|
49
|
-
return tokens[1..], enum
|
49
|
+
return tokens[1..tokens.size], enum
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_union(tokens)
|
53
|
+
count = 0
|
54
|
+
union_hash = {}
|
55
|
+
# type A_UNION ( int | uint | data = 7 | f32 )
|
56
|
+
while tokens[0] != :close_paren
|
57
|
+
if tokens[0] == :bar
|
58
|
+
tokens = tokens[1..tokens.size]
|
59
|
+
else
|
60
|
+
if tokens[1] == :equal
|
61
|
+
raise SchemaParsingException.new("Equals sign in union must be followed by a number") unless tokens[2].is_a?(Numeric)
|
62
|
+
count = tokens[2]
|
63
|
+
tokens, type = self.parse(tokens)
|
64
|
+
tokens = tokens[2..tokens.size]
|
65
|
+
union_hash[count] = type
|
66
|
+
count += 1
|
67
|
+
else
|
68
|
+
tokens, type = self.parse(tokens)
|
69
|
+
union_hash[count] = type
|
70
|
+
count += 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return tokens, union_hash
|
50
75
|
end
|
51
76
|
|
52
77
|
def parse_struct(tokens)
|
53
78
|
struct_fields = {}
|
54
79
|
while tokens.size >= 2 and tokens[1] == :colon
|
55
80
|
name = tokens[0]
|
56
|
-
tokens, type = self.parse(tokens[2..])
|
81
|
+
tokens, type = self.parse(tokens[2..tokens.size])
|
57
82
|
struct_fields[name.to_sym] = type
|
58
83
|
end
|
59
|
-
return tokens[1..], struct_fields
|
84
|
+
return tokens[1..tokens.size], struct_fields
|
60
85
|
end
|
61
86
|
|
62
87
|
def parse(tokens)
|
63
88
|
while tokens.size > 0
|
64
89
|
if tokens[0] == "type"
|
65
90
|
name = tokens[1]
|
66
|
-
tokens, type = self.parse(tokens[2..])
|
91
|
+
tokens, type = self.parse(tokens[2..tokens.size])
|
67
92
|
@definitions[name.to_sym] = type
|
68
93
|
elsif tokens[0] == "map"
|
69
|
-
raise SchemaParsingException("Map must be followed by a '[' eg. map[string]data") if tokens[1] != :open_brace
|
70
|
-
tokens, map_from_type = parse(tokens[2..])
|
71
|
-
raise SchemaParsingException("Map to type must be followed by a ']' eg. map[string]data") if tokens[0] != :close_brace
|
72
|
-
tokens, map_to_type = parse(tokens[1..])
|
73
|
-
return tokens, Bare.Map(map_from_type,map_to_type)
|
94
|
+
raise SchemaParsingException.new("Map must be followed by a '[' eg. map[string]data") if tokens[1] != :open_brace
|
95
|
+
tokens, map_from_type = parse(tokens[2..tokens.size])
|
96
|
+
raise SchemaParsingException.new("Map to type must be followed by a ']' eg. map[string]data") if tokens[0] != :close_brace
|
97
|
+
tokens, map_to_type = parse(tokens[1..tokens.size])
|
98
|
+
return tokens, Bare.Map(map_from_type, map_to_type)
|
99
|
+
elsif tokens[0] == "data" && tokens.size > 3 && tokens[1] == :less_than
|
100
|
+
raise SchemaParsingException.new("data< must be followed by a number for a fixed sized bare data") unless tokens[2].is_a?(Numeric)
|
101
|
+
raise SchemaParsingException.new("data<# must be followed by a >") unless tokens[3] == :greater_than
|
102
|
+
return tokens[4..tokens.size], Bare.DataFixedLen(tokens[2])
|
74
103
|
elsif tokens[0] == "enum"
|
75
104
|
name = tokens[1]
|
76
|
-
raise SchemaParsingException("Enum must be followed by a '{'") if tokens[2] != :open_block
|
77
|
-
tokens, enum = parse_enum(tokens[3..])
|
105
|
+
raise SchemaParsingException.new("Enum must be followed by a '{'") if tokens[2] != :open_block
|
106
|
+
tokens, enum = parse_enum(tokens[3..tokens.size])
|
78
107
|
@definitions[name.to_sym] = enum
|
79
|
-
|
108
|
+
elsif tokens[0] == "optional"
|
109
|
+
raise SchemaParsingException.new("Optional must be followed by a '< TYPE > you are missing the first <'") if tokens[1] != :less_than
|
110
|
+
tokens, optional_type = self.parse(tokens[2..tokens.size])
|
111
|
+
raise SchemaParsingException.new("Optional must be followed by a '< TYPE >' you are missing the last >") if tokens[0] != :greater_than
|
112
|
+
return tokens[1..tokens.size], Bare.Optional(optional_type)
|
80
113
|
elsif tokens[0] == :open_brace
|
81
|
-
|
82
|
-
|
114
|
+
if tokens[1].is_a?(Numeric)
|
115
|
+
size = tokens[1]
|
116
|
+
raise SchemaParsingException.new("Fixed Length Array size must be followed by a ']'") if tokens[2] != :close_brace
|
117
|
+
tokens, arr_type = parse(tokens[3..tokens.size])
|
118
|
+
return tokens, Bare.ArrayFixedLen(arr_type, size)
|
119
|
+
else
|
120
|
+
tokens, arr_type = parse(tokens[2..tokens.size])
|
121
|
+
return tokens, Bare.Array(arr_type)
|
122
|
+
end
|
123
|
+
elsif tokens[0] == :open_paren
|
124
|
+
tokens, union_hash = parse_union(tokens[1..tokens.size])
|
125
|
+
raise SchemaParsingException.new("Union must be followed by a ')'") if tokens[0] != :close_paren
|
126
|
+
return tokens[1..tokens.size], Bare.Union(union_hash)
|
83
127
|
elsif tokens[0] == :open_block
|
84
|
-
tokens, struct_fields = parse_struct(tokens[1..])
|
128
|
+
tokens, struct_fields = parse_struct(tokens[1..tokens.size])
|
85
129
|
strct = Bare.Struct(struct_fields)
|
86
130
|
return tokens, strct
|
87
131
|
elsif @primitives.include?(tokens[0])
|
88
132
|
type = @primitives[tokens[0]]
|
89
|
-
return tokens[1..], type
|
133
|
+
return tokens[1..tokens.size], type
|
134
|
+
elsif @definitions.keys.include?(tokens[0].to_sym) # User defined type
|
135
|
+
return tokens[1..tokens.size], tokens[0].to_sym
|
136
|
+
elsif tokens[0].is_a?(String) && tokens[0][0].upcase == tokens[0][0] # Not yet defined user type
|
137
|
+
return tokens[1..tokens.size], tokens[0].to_sym
|
90
138
|
else
|
91
139
|
raise SchemaParsingException.new("Unable to parse token: #{tokens[0]}")
|
92
140
|
end
|