bare-rb 0.0.0 → 0.1.5
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 +62 -6
- data/lib/exceptions.rb +19 -0
- data/lib/lexer.rb +62 -0
- data/lib/parser.rb +150 -0
- data/lib/types.rb +174 -78
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e8e36acbdcc47dc92e23a029edf5fac7001fbec9bd4948549cc0e682ea238b0
|
4
|
+
data.tar.gz: 86ffe342e8f2ec768b6fb222fe3575dd35eda7500ee88cff7111056a8bd422d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 555833846daa3aa6337fb836b3a7959d656dd329c3925bceb01ab27d6f873bde95e83bf965daea90f3429c73b8659b40929f6f9e1b138a631c85966910750ee2
|
7
|
+
data.tar.gz: 0f9b6ef29fd8731c688f8507d6b141e2bb0992b0074b7118cb8b13a9263b57aad9e30becbb990c94d6cc33792abad805a3cd4a44d8deab93ee3847a8de57e68a
|
data/lib/bare-rb.rb
CHANGED
@@ -1,13 +1,67 @@
|
|
1
1
|
require 'set'
|
2
2
|
require_relative "types"
|
3
|
+
require_relative "lexer"
|
4
|
+
require_relative "parser"
|
3
5
|
|
4
6
|
class Bare
|
5
|
-
def self.encode(msg, schema)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
def self.encode(msg, schema, type=nil)
|
8
|
+
if schema.is_a?(Bare::Schema)
|
9
|
+
raise NoTypeProvided("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?
|
10
|
+
schema[type].encode(msg)
|
11
|
+
else
|
12
|
+
schema.encode(msg)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.decode(msg, schema, type=nil)
|
17
|
+
if schema.is_a?(Bare::Schema)
|
18
|
+
raise NoTypeProvided("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?
|
19
|
+
value, rest = schema[type].decode(msg)
|
20
|
+
value
|
21
|
+
else
|
22
|
+
value, rest = schema.decode(msg)
|
23
|
+
return value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.parse_schema(path)
|
28
|
+
# Hash of class names to BARE ASTs
|
29
|
+
# Eg. types['Customer'] == Bare.i32
|
30
|
+
types = parser(lexer(path))
|
31
|
+
Bare.Schema(types)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.Schema(hash)
|
35
|
+
Bare::Schema.new(hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
class Schema
|
39
|
+
def ==(otherSchema)
|
40
|
+
return false unless otherSchema.is_a?(Bare::Schema)
|
41
|
+
@types == otherSchema.types
|
42
|
+
end
|
43
|
+
|
44
|
+
def types
|
45
|
+
@types
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](key)
|
49
|
+
return @types[key]
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(types)
|
53
|
+
@types = types
|
54
|
+
@types.keys.each do |key|
|
55
|
+
if @types[key].is_a?(Symbol)
|
56
|
+
@types[key] = @types[@types[key]]
|
57
|
+
else
|
58
|
+
# Users may use symbols to reference not yet defined types
|
59
|
+
# here we recursively call our bare classes to finalize their types
|
60
|
+
# replacing Symbols like :SomeType with a reference to the other type
|
61
|
+
@types[key].finalize_references(@types)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
11
65
|
end
|
12
66
|
|
13
67
|
# These classes are wrapped in methods for ergonomics.
|
@@ -108,5 +162,7 @@ class Bare
|
|
108
162
|
def self.Enum(*opts)
|
109
163
|
return BareTypes::Enum.new(*opts)
|
110
164
|
end
|
165
|
+
|
166
|
+
|
111
167
|
end
|
112
168
|
|
data/lib/exceptions.rb
CHANGED
@@ -1,9 +1,28 @@
|
|
1
|
+
|
1
2
|
class BareException < StandardError
|
2
3
|
def initialize(msg=nil)
|
3
4
|
super
|
4
5
|
end
|
5
6
|
end
|
6
7
|
|
8
|
+
class FixedDataSizeWrong < BareException
|
9
|
+
def initialize(msg=nil)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class NoTypeProvided < BareException
|
15
|
+
def initialize(msg = nil)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class SchemaParsingException < BareException
|
21
|
+
def initialize(msg=nil)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
7
26
|
class VoidUsedOutsideTaggedSet < BareException
|
8
27
|
def initialize(msg = "Any type which is ultimately a void type (either directly or through user-defined types) may not be used as an optional type, struct member, array member, or map key or value. Void types may only be used as members of the set of types in a tagged union.")
|
9
28
|
super
|
data/lib/lexer.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative './exceptions'
|
2
|
+
|
3
|
+
def lexer(path)
|
4
|
+
tokens = []
|
5
|
+
line_num = 0
|
6
|
+
File.open(path).each do |line|
|
7
|
+
while line.size > 0
|
8
|
+
if /^#/.match(line)
|
9
|
+
break
|
10
|
+
elsif /^\n/.match(line)
|
11
|
+
break
|
12
|
+
elsif /^ /.match(line)
|
13
|
+
line = line[1..line.size]
|
14
|
+
elsif /^</.match(line)
|
15
|
+
line = line[1..line.size]
|
16
|
+
tokens << :less_than
|
17
|
+
elsif /^>/.match(line)
|
18
|
+
line = line[1..line.size]
|
19
|
+
tokens << :greater_than
|
20
|
+
next
|
21
|
+
elsif /^{/.match(line)
|
22
|
+
line = line[1..line.size]
|
23
|
+
tokens << :open_block
|
24
|
+
elsif /^=/.match(line)
|
25
|
+
line = line[1..line.size]
|
26
|
+
tokens << :equal
|
27
|
+
elsif /^}/.match(line)
|
28
|
+
line = line[1..line.size]
|
29
|
+
tokens << :close_block
|
30
|
+
elsif /^\[/.match(line)
|
31
|
+
line = line[1..line.size]
|
32
|
+
tokens << :open_brace
|
33
|
+
elsif /^\]/.match(line)
|
34
|
+
line = line[1..line.size]
|
35
|
+
tokens << :close_brace
|
36
|
+
elsif /^\(/.match(line)
|
37
|
+
line = line[1..line.size]
|
38
|
+
tokens << :open_paren
|
39
|
+
elsif /^\)/.match(line)
|
40
|
+
line = line[1..line.size]
|
41
|
+
tokens << :close_paren
|
42
|
+
elsif /^\|/.match(line)
|
43
|
+
line = line[1..line.size]
|
44
|
+
tokens << :bar
|
45
|
+
elsif match = /^([0-9]+)/.match(line)
|
46
|
+
tokens << match[0].to_i
|
47
|
+
line = line[(match[0].size)..line.size]
|
48
|
+
next
|
49
|
+
elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]+/.match(line)
|
50
|
+
tokens << match[0]
|
51
|
+
line = line[(match[0].size)..line.size]
|
52
|
+
elsif /:/.match(line)
|
53
|
+
tokens << :colon
|
54
|
+
line = line[1..line.size]
|
55
|
+
else
|
56
|
+
raise SchemaParsingException.new("Unable to lex line #{line_num} near #{line.inspect}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
line_num += 1
|
60
|
+
end
|
61
|
+
return tokens
|
62
|
+
end
|
data/lib/parser.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require_relative './exceptions'
|
2
|
+
|
3
|
+
|
4
|
+
# enum, struct, array, fixedlenarray, data<length>
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@definitions = {}
|
9
|
+
@primitives = {
|
10
|
+
"uint" => Bare.Uint,
|
11
|
+
"int" => Bare.Int,
|
12
|
+
"u8" => Bare.U8,
|
13
|
+
"u16" => Bare.U16,
|
14
|
+
"u32" => Bare.U32,
|
15
|
+
"u64" => Bare.U64,
|
16
|
+
"i8" => Bare.I8,
|
17
|
+
"i16" => Bare.I16,
|
18
|
+
"i32" => Bare.I32,
|
19
|
+
"i64" => Bare.I64,
|
20
|
+
"f32" => Bare.F32,
|
21
|
+
"f64" => Bare.F64,
|
22
|
+
"bool" => Bare.Bool,
|
23
|
+
"string" => Bare.String,
|
24
|
+
"data" => Bare.Data,
|
25
|
+
"void" => Bare.Void,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def definitions
|
30
|
+
@definitions
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_enum(tokens)
|
34
|
+
enum_hash = {} # {1 => "abc", 5 => :cow, 16382 => 123}
|
35
|
+
count = 0
|
36
|
+
while tokens[0] != :close_block
|
37
|
+
if tokens[1] == :equal
|
38
|
+
name = tokens[0]
|
39
|
+
int_repr = tokens[2]
|
40
|
+
enum_hash[int_repr] = name
|
41
|
+
tokens = tokens[3..tokens.size]
|
42
|
+
else
|
43
|
+
enum_hash[count] = tokens[0]
|
44
|
+
count += 1
|
45
|
+
tokens = tokens[1..tokens.size]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
enum = Bare.Enum(enum_hash)
|
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
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_struct(tokens)
|
78
|
+
struct_fields = {}
|
79
|
+
while tokens.size >= 2 and tokens[1] == :colon
|
80
|
+
name = tokens[0]
|
81
|
+
tokens, type = self.parse(tokens[2..tokens.size])
|
82
|
+
struct_fields[name.to_sym] = type
|
83
|
+
end
|
84
|
+
return tokens[1..tokens.size], struct_fields
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse(tokens)
|
88
|
+
while tokens.size > 0
|
89
|
+
if tokens[0] == "type"
|
90
|
+
name = tokens[1]
|
91
|
+
tokens, type = self.parse(tokens[2..tokens.size])
|
92
|
+
@definitions[name.to_sym] = type
|
93
|
+
elsif tokens[0] == "map"
|
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])
|
103
|
+
elsif tokens[0] == "enum"
|
104
|
+
name = tokens[1]
|
105
|
+
raise SchemaParsingException.new("Enum must be followed by a '{'") if tokens[2] != :open_block
|
106
|
+
tokens, enum = parse_enum(tokens[3..tokens.size])
|
107
|
+
@definitions[name.to_sym] = enum
|
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)
|
113
|
+
elsif tokens[0] == :open_brace
|
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)
|
127
|
+
elsif tokens[0] == :open_block
|
128
|
+
tokens, struct_fields = parse_struct(tokens[1..tokens.size])
|
129
|
+
strct = Bare.Struct(struct_fields)
|
130
|
+
return tokens, strct
|
131
|
+
elsif @primitives.include?(tokens[0])
|
132
|
+
type = @primitives[tokens[0]]
|
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], @definitions[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
|
138
|
+
else
|
139
|
+
raise SchemaParsingException.new("Unable to parse token: #{tokens[0]}")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def parser(tokens, definitions = {})
|
147
|
+
parser = Parser.new
|
148
|
+
parser.parse(tokens)
|
149
|
+
return parser.definitions
|
150
|
+
end
|
data/lib/types.rb
CHANGED
@@ -3,16 +3,26 @@ require_relative './exceptions'
|
|
3
3
|
class BareTypes
|
4
4
|
|
5
5
|
class BaseType
|
6
|
+
def initialize
|
7
|
+
@finalized = false
|
8
|
+
super
|
9
|
+
end
|
6
10
|
end
|
7
11
|
|
8
12
|
class BarePrimitive < BaseType
|
13
|
+
|
9
14
|
# Types which are always equivalent to another instantiation of themselves
|
10
15
|
# Eg. Uint.new == Uint.new
|
11
16
|
# But Union.new(types1) != Union.new(types2)
|
12
17
|
# since unions could have different sets of types
|
18
|
+
|
13
19
|
def ==(other)
|
14
20
|
self.class == other.class
|
15
21
|
end
|
22
|
+
|
23
|
+
def finalize_references(schema)
|
24
|
+
end
|
25
|
+
|
16
26
|
end
|
17
27
|
|
18
28
|
class Int < BarePrimitive
|
@@ -22,11 +32,11 @@ class BareTypes
|
|
22
32
|
mappedInteger = msg < 0 ? -2 * msg - 1 : msg * 2
|
23
33
|
return Uint.new.encode(mappedInteger)
|
24
34
|
end
|
35
|
+
|
25
36
|
def decode(msg)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return { value: unmapped, rest: output[:rest] }
|
37
|
+
value, rest = Uint.new.decode(msg)
|
38
|
+
value = value.odd? ? (value + 1) / -2 : value / 2
|
39
|
+
return value, rest
|
30
40
|
end
|
31
41
|
end
|
32
42
|
|
@@ -34,17 +44,19 @@ class BareTypes
|
|
34
44
|
def encode(msg)
|
35
45
|
return "".b
|
36
46
|
end
|
47
|
+
|
37
48
|
def decode(msg)
|
38
|
-
return
|
49
|
+
return nil, msg
|
39
50
|
end
|
40
51
|
end
|
41
52
|
|
42
53
|
class F32 < BarePrimitive
|
43
54
|
def encode(msg)
|
44
|
-
|
55
|
+
[msg].pack("e")
|
45
56
|
end
|
57
|
+
|
46
58
|
def decode(msg)
|
47
|
-
return
|
59
|
+
return msg.unpack("e")[0], msg[4..msg.size]
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
@@ -52,8 +64,9 @@ class BareTypes
|
|
52
64
|
def encode(msg)
|
53
65
|
return [msg].pack("E")
|
54
66
|
end
|
67
|
+
|
55
68
|
def decode(msg)
|
56
|
-
return
|
69
|
+
return msg.unpack("E")[0], msg[8..msg.size]
|
57
70
|
end
|
58
71
|
end
|
59
72
|
|
@@ -69,11 +82,11 @@ class BareTypes
|
|
69
82
|
bytes << encodedString
|
70
83
|
return bytes
|
71
84
|
end
|
85
|
+
|
72
86
|
def decode(msg)
|
73
|
-
|
74
|
-
|
75
|
-
string
|
76
|
-
return {value: string.force_encoding("utf-8"), rest: output[:rest][strLen..output[:rest].size] }
|
87
|
+
strLen, rest = Uint.new.decode(msg)
|
88
|
+
string = rest[0..strLen - 1]
|
89
|
+
return string.force_encoding("utf-8"), rest[strLen..rest.size]
|
77
90
|
end
|
78
91
|
end
|
79
92
|
|
@@ -82,6 +95,16 @@ class BareTypes
|
|
82
95
|
return otherType.class == BareTypes::Optional && otherType.optionalType == @optionalType
|
83
96
|
end
|
84
97
|
|
98
|
+
def finalize_references(schema)
|
99
|
+
return if @finalized
|
100
|
+
@finalized = true
|
101
|
+
if @optionalType.is_a?(Symbol)
|
102
|
+
@optionalType = schema[@optionalType]
|
103
|
+
else
|
104
|
+
@optionalType.finalize_references(schema)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
85
108
|
def optionalType
|
86
109
|
@optionalType
|
87
110
|
end
|
@@ -95,7 +118,7 @@ class BareTypes
|
|
95
118
|
if msg.nil?
|
96
119
|
return "\x00".b
|
97
120
|
else
|
98
|
-
bytes = "\
|
121
|
+
bytes = "\x01".b
|
99
122
|
bytes << @optionalType.encode(msg)
|
100
123
|
return bytes
|
101
124
|
end
|
@@ -103,7 +126,7 @@ class BareTypes
|
|
103
126
|
|
104
127
|
def decode(msg)
|
105
128
|
if msg.unpack("C")[0] == 0
|
106
|
-
return
|
129
|
+
return nil, msg[1..msg.size]
|
107
130
|
else
|
108
131
|
return @optionalType.decode(msg[1..msg.size])
|
109
132
|
end
|
@@ -115,9 +138,23 @@ class BareTypes
|
|
115
138
|
return otherType.class == BareTypes::Map && otherType.from == @from && otherType.to == @to
|
116
139
|
end
|
117
140
|
|
141
|
+
def finalize_references(schema)
|
142
|
+
return if @finalized
|
143
|
+
@finalized = true
|
144
|
+
if @from.is_a?(Symbol)
|
145
|
+
@to = schema[@to]
|
146
|
+
else
|
147
|
+
@to.finalize_references(schema)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
118
151
|
def initialize(fromType, toType)
|
119
152
|
raise VoidUsedOutsideTaggedSet if fromType.class == BareTypes::Void or toType.class == BareTypes::Void
|
120
|
-
|
153
|
+
if !fromType.class.ancestors.include?(BarePrimitive) ||
|
154
|
+
fromType.is_a?(BareTypes::Data) ||
|
155
|
+
fromType.is_a?(BareTypes::DataFixedLen)
|
156
|
+
raise MapKeyError("Map keys must use a primitive type which is not data or data<length>.")
|
157
|
+
end
|
121
158
|
@from = fromType
|
122
159
|
@to = toType
|
123
160
|
end
|
@@ -141,24 +178,34 @@ class BareTypes
|
|
141
178
|
|
142
179
|
def decode(msg)
|
143
180
|
hash = Hash.new
|
144
|
-
|
145
|
-
mapSize = output[:value]
|
181
|
+
mapSize, rest = Uint.new.decode(msg)
|
146
182
|
(mapSize - 1).to_i.downto(0) do
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
hash[key] = output[:value]
|
151
|
-
hash[key] = output[:value]
|
183
|
+
key, rest = @from.decode(rest)
|
184
|
+
value, rest = @to.decode(rest)
|
185
|
+
hash[key] = value
|
152
186
|
end
|
153
|
-
return
|
187
|
+
return hash, rest
|
154
188
|
end
|
155
189
|
end
|
156
190
|
|
157
191
|
class Union < BarePrimitive
|
192
|
+
|
158
193
|
def intToType
|
159
194
|
@intToType
|
160
195
|
end
|
161
196
|
|
197
|
+
def finalize_references(schema)
|
198
|
+
return if @finalized
|
199
|
+
@finalized = true
|
200
|
+
@intToType.keys.each do |key|
|
201
|
+
if @intToType[key].is_a?(Symbol)
|
202
|
+
@intToType[key] = schema[@intToType[key]]
|
203
|
+
else
|
204
|
+
@intToType[key].finalize_references(schema)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
162
209
|
def ==(otherType)
|
163
210
|
return false unless otherType.is_a?(BareTypes::Union)
|
164
211
|
@intToType.each do |int, type|
|
@@ -194,11 +241,10 @@ class BareTypes
|
|
194
241
|
end
|
195
242
|
|
196
243
|
def decode(msg)
|
197
|
-
|
198
|
-
int = unionTypeInt[:value]
|
244
|
+
int, rest = Uint.new.decode(msg)
|
199
245
|
type = @intToType[int]
|
200
|
-
value = type.decode(
|
201
|
-
return {value:
|
246
|
+
value, rest = type.decode(rest)
|
247
|
+
return {value: value, type: type}, rest
|
202
248
|
end
|
203
249
|
end
|
204
250
|
|
@@ -211,21 +257,31 @@ class BareTypes
|
|
211
257
|
return @length
|
212
258
|
end
|
213
259
|
|
260
|
+
def finalize_references(schema)
|
261
|
+
end
|
262
|
+
|
214
263
|
def initialize(length)
|
215
264
|
raise MinimumSizeError("DataFixedLen must have a length greater than 0, got: #{length.inspect}") if length < 1
|
216
265
|
@length = length
|
217
266
|
end
|
218
267
|
|
219
268
|
def encode(msg)
|
220
|
-
|
269
|
+
if msg.size != @length
|
270
|
+
raise FixedDataSizeWrong.new("Message is not proper sized for DataFixedLen should have been #{@length} but was #{msg.size}")
|
271
|
+
end
|
272
|
+
msg
|
221
273
|
end
|
222
274
|
|
223
275
|
def decode(msg)
|
224
|
-
return
|
276
|
+
return msg[0..@length], msg[@length..msg.size]
|
225
277
|
end
|
226
278
|
end
|
227
279
|
|
228
280
|
class Data < BarePrimitive
|
281
|
+
|
282
|
+
def finalize_references(schema)
|
283
|
+
end
|
284
|
+
|
229
285
|
def encode(msg)
|
230
286
|
bytes = Uint.new.encode(msg.size)
|
231
287
|
bytes << msg
|
@@ -233,14 +289,16 @@ class BareTypes
|
|
233
289
|
end
|
234
290
|
|
235
291
|
def decode(msg)
|
236
|
-
|
237
|
-
rest
|
238
|
-
dataSize = output[:value]
|
239
|
-
return {value: rest[0..dataSize], rest: rest[dataSize..rest.size]}
|
292
|
+
dataSize, rest = Uint.new.decode(msg)
|
293
|
+
return rest[0..dataSize - 1], rest[dataSize..rest.size]
|
240
294
|
end
|
241
295
|
end
|
242
296
|
|
243
297
|
class Uint < BarePrimitive
|
298
|
+
|
299
|
+
def finalize_references(schema)
|
300
|
+
end
|
301
|
+
|
244
302
|
def encode(msg)
|
245
303
|
bytes = "".b
|
246
304
|
_get_next_7_bits_as_byte(msg, 128) do |byte|
|
@@ -259,7 +317,7 @@ class BareTypes
|
|
259
317
|
end
|
260
318
|
|
261
319
|
def decode(msg)
|
262
|
-
ints = msg.unpack("
|
320
|
+
ints = msg.unpack("CCCCCCCC")
|
263
321
|
relevantInts = []
|
264
322
|
i = 0
|
265
323
|
while ints[i] & 0b10000000 == 128
|
@@ -271,7 +329,7 @@ class BareTypes
|
|
271
329
|
relevantInts.each_with_index do |int, idx|
|
272
330
|
sum += int << (idx * 7)
|
273
331
|
end
|
274
|
-
return
|
332
|
+
return sum, msg[(i + 1)..msg.size]
|
275
333
|
end
|
276
334
|
end
|
277
335
|
|
@@ -281,7 +339,7 @@ class BareTypes
|
|
281
339
|
end
|
282
340
|
|
283
341
|
def decode(msg)
|
284
|
-
return
|
342
|
+
return msg[0].unpack("C")[0], msg[1..msg.size]
|
285
343
|
end
|
286
344
|
end
|
287
345
|
|
@@ -291,7 +349,7 @@ class BareTypes
|
|
291
349
|
end
|
292
350
|
|
293
351
|
def decode(msg)
|
294
|
-
return
|
352
|
+
return msg.unpack("v")[0], msg[2..msg.size]
|
295
353
|
end
|
296
354
|
end
|
297
355
|
|
@@ -301,7 +359,7 @@ class BareTypes
|
|
301
359
|
end
|
302
360
|
|
303
361
|
def decode(msg)
|
304
|
-
return
|
362
|
+
return msg.unpack("V")[0], msg[4..msg.size]
|
305
363
|
end
|
306
364
|
end
|
307
365
|
|
@@ -311,7 +369,7 @@ class BareTypes
|
|
311
369
|
end
|
312
370
|
|
313
371
|
def decode(msg)
|
314
|
-
return
|
372
|
+
return msg.unpack("Q")[0], msg[8..msg.size]
|
315
373
|
end
|
316
374
|
end
|
317
375
|
|
@@ -321,7 +379,7 @@ class BareTypes
|
|
321
379
|
end
|
322
380
|
|
323
381
|
def decode(msg)
|
324
|
-
return
|
382
|
+
return msg[0].unpack("c")[0], msg[1..msg.size]
|
325
383
|
end
|
326
384
|
end
|
327
385
|
|
@@ -331,7 +389,7 @@ class BareTypes
|
|
331
389
|
end
|
332
390
|
|
333
391
|
def decode(msg)
|
334
|
-
return
|
392
|
+
return msg.unpack('s<')[0], msg[2..msg.size]
|
335
393
|
end
|
336
394
|
end
|
337
395
|
|
@@ -341,7 +399,7 @@ class BareTypes
|
|
341
399
|
end
|
342
400
|
|
343
401
|
def decode(msg)
|
344
|
-
return
|
402
|
+
return msg.unpack('l<')[0], msg[4..msg.size]
|
345
403
|
end
|
346
404
|
end
|
347
405
|
|
@@ -351,7 +409,7 @@ class BareTypes
|
|
351
409
|
end
|
352
410
|
|
353
411
|
def decode(msg)
|
354
|
-
return
|
412
|
+
return msg.unpack('q<')[0], msg[8..msg.size]
|
355
413
|
end
|
356
414
|
end
|
357
415
|
|
@@ -361,11 +419,16 @@ class BareTypes
|
|
361
419
|
end
|
362
420
|
|
363
421
|
def decode(msg)
|
364
|
-
return
|
422
|
+
return (msg == "\x00\x00" ? false : true), msg[1..msg.size]
|
365
423
|
end
|
366
424
|
end
|
367
425
|
|
368
426
|
class Struct < BaseType
|
427
|
+
|
428
|
+
def [](key)
|
429
|
+
return @mapping[key]
|
430
|
+
end
|
431
|
+
|
369
432
|
def ==(otherType)
|
370
433
|
return false unless otherType.class == BareTypes::Struct
|
371
434
|
@mapping.each do |k, v|
|
@@ -374,16 +437,31 @@ class BareTypes
|
|
374
437
|
return true
|
375
438
|
end
|
376
439
|
|
440
|
+
def finalize_references(schema)
|
441
|
+
return if @finalized
|
442
|
+
@finalized = true
|
443
|
+
@mapping.each do |key, val|
|
444
|
+
if val.is_a?(Symbol)
|
445
|
+
@mapping[key] = schema[val]
|
446
|
+
else
|
447
|
+
val.finalize_references(schema)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
377
452
|
def mapping
|
378
453
|
@mapping
|
379
454
|
end
|
380
455
|
|
381
456
|
def initialize(symbolToType)
|
382
|
-
# Mapping from symbols to Bare types
|
457
|
+
# Mapping from symbols to Bare types (or possibly symbols before finalizing)
|
383
458
|
symbolToType.keys.each do |k|
|
384
|
-
raise BareException("Struct keys must be symbols") unless k.is_a?(Symbol)
|
385
|
-
|
386
|
-
|
459
|
+
raise BareException.new("Struct keys must be symbols") unless k.is_a?(Symbol)
|
460
|
+
if (!symbolToType[k].class.ancestors.include?(BaseType) && !symbolToType[k].is_a?(Symbol))
|
461
|
+
raise BareException.new("Struct values must be a BareTypes::TYPE or a symbol with the same
|
462
|
+
name as a user defined type\nInstead got: #{symbolToType[k].inspect}")
|
463
|
+
end
|
464
|
+
raise VoidUsedOutsideTaggedSet.new("Void types may only be used as members of the set of types in a tagged union. Void type used as struct key") if symbolToType.class == BareTypes::Void
|
387
465
|
end
|
388
466
|
raise("Struct must have at least one field") if symbolToType.keys.size == 0
|
389
467
|
@mapping = symbolToType
|
@@ -392,7 +470,7 @@ class BareTypes
|
|
392
470
|
def encode(msg)
|
393
471
|
bytes = "".b
|
394
472
|
@mapping.keys.each do |symbol|
|
395
|
-
raise SchemaMismatch("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
|
473
|
+
raise SchemaMismatch.new("All struct fields must be specified, missing: #{symbol.inspect}") unless msg.keys.include?(symbol)
|
396
474
|
bytes << @mapping[symbol].encode(msg[symbol])
|
397
475
|
end
|
398
476
|
return bytes
|
@@ -402,11 +480,10 @@ class BareTypes
|
|
402
480
|
hash = Hash.new
|
403
481
|
rest = msg
|
404
482
|
@mapping.keys.each do |symbol|
|
405
|
-
|
406
|
-
hash[symbol] =
|
407
|
-
rest = output[:rest]
|
483
|
+
value, rest = @mapping[symbol].decode(rest)
|
484
|
+
hash[symbol] = value
|
408
485
|
end
|
409
|
-
return
|
486
|
+
return hash, rest
|
410
487
|
end
|
411
488
|
end
|
412
489
|
|
@@ -419,8 +496,18 @@ class BareTypes
|
|
419
496
|
return @type
|
420
497
|
end
|
421
498
|
|
499
|
+
def finalize_references(schema)
|
500
|
+
return if @finalized
|
501
|
+
@finalized = true
|
502
|
+
if @type.is_a?(Symbol)
|
503
|
+
@type = schema[@type]
|
504
|
+
else
|
505
|
+
@type.finalize_references(schema)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
422
509
|
def initialize(type)
|
423
|
-
raise VoidUsedOutsideTaggedSet("Void types may only be used as members of the set of types in a tagged union.") if type.class == BareTypes::Void
|
510
|
+
raise VoidUsedOutsideTaggedSet.new("Void types may only be used as members of the set of types in a tagged union.") if type.class == BareTypes::Void
|
424
511
|
@type = type
|
425
512
|
end
|
426
513
|
|
@@ -433,17 +520,16 @@ class BareTypes
|
|
433
520
|
end
|
434
521
|
|
435
522
|
def decode(msg)
|
436
|
-
output = Uint.new.decode(msg)
|
437
523
|
arr = []
|
438
|
-
arrayLen =
|
524
|
+
arrayLen, rest = Uint.new.decode(msg)
|
439
525
|
lastSize = msg.size + 1 # Make sure msg size monotonically decreasing
|
440
526
|
(arrayLen - 1).downto(0) do
|
441
|
-
|
442
|
-
arr <<
|
443
|
-
break if
|
444
|
-
lastSize =
|
527
|
+
arrVal, rest = @type.decode(rest)
|
528
|
+
arr << arrVal
|
529
|
+
break if rest.nil? || rest.size == 0 || lastSize <= rest.size
|
530
|
+
lastSize = rest.size
|
445
531
|
end
|
446
|
-
return
|
532
|
+
return arr, rest
|
447
533
|
end
|
448
534
|
end
|
449
535
|
|
@@ -452,11 +538,21 @@ class BareTypes
|
|
452
538
|
return otherType.class == BareTypes::ArrayFixedLen && otherType.type == @type && otherType.size == @size
|
453
539
|
end
|
454
540
|
|
541
|
+
def finalize_references(schema)
|
542
|
+
return if @finalized
|
543
|
+
@finalized = true
|
544
|
+
if @type.is_a?(Symbol)
|
545
|
+
@type = schema[@type]
|
546
|
+
else
|
547
|
+
@type.finalize_references(schema)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
455
551
|
def initialize(type, size)
|
456
552
|
@type = type
|
457
553
|
@size = size
|
458
|
-
raise VoidUsedOutsideTaggedSet("Void type may not be used as type of fixed length array.") if type.class == BareTypes::Void
|
459
|
-
raise MinimumSizeError("FixedLenArray size must be > 0") if size < 1
|
554
|
+
raise VoidUsedOutsideTaggedSet.new("Void type may not be used as type of fixed length array.") if type.class == BareTypes::Void
|
555
|
+
raise MinimumSizeError.new("FixedLenArray size must be > 0") if size < 1
|
460
556
|
end
|
461
557
|
|
462
558
|
def type
|
@@ -468,7 +564,7 @@ class BareTypes
|
|
468
564
|
end
|
469
565
|
|
470
566
|
def encode(arr)
|
471
|
-
raise SchemaMismatch("This FixLenArray is of length #{@size.to_s} but you passed an array of length #{arr.size}") if arr.size != @size
|
567
|
+
raise SchemaMismatch.new("This FixLenArray is of length #{@size.to_s} but you passed an array of length #{arr.size}") if arr.size != @size
|
472
568
|
bytes = ""
|
473
569
|
arr.each do |item|
|
474
570
|
bytes << @type.encode(item)
|
@@ -476,15 +572,13 @@ class BareTypes
|
|
476
572
|
return bytes
|
477
573
|
end
|
478
574
|
|
479
|
-
def decode(
|
575
|
+
def decode(rest)
|
480
576
|
array = []
|
481
|
-
rest = msg
|
482
577
|
@size.times do
|
483
|
-
|
484
|
-
|
485
|
-
array << output[:value]
|
578
|
+
arrVal, rest = @type.decode(rest)
|
579
|
+
array << arrVal
|
486
580
|
end
|
487
|
-
return
|
581
|
+
return array, rest
|
488
582
|
end
|
489
583
|
end
|
490
584
|
|
@@ -497,6 +591,10 @@ class BareTypes
|
|
497
591
|
return true
|
498
592
|
end
|
499
593
|
|
594
|
+
|
595
|
+
def finalize_references(schema)
|
596
|
+
end
|
597
|
+
|
500
598
|
def intToVal
|
501
599
|
@intToVal
|
502
600
|
end
|
@@ -504,9 +602,9 @@ class BareTypes
|
|
504
602
|
def initialize(source)
|
505
603
|
@intToVal = {}
|
506
604
|
@valToInt = {}
|
507
|
-
raise BareException("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
|
508
|
-
raise BareException("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
|
509
|
-
raise
|
605
|
+
raise BareException.new("Enum must initialized with a hash from integers to anything") if !source.is_a?(Hash)
|
606
|
+
raise BareException.new("Enum must have unique positive integer assignments") if Set.new(source.keys).size != source.keys.size
|
607
|
+
raise EnumValueError.new("Enum must have unique values") if source.values.to_set.size != source.values.size
|
510
608
|
source.each do |k, v|
|
511
609
|
raise("Enum keys must be positive integers") if k < 0
|
512
610
|
@intToVal[k.to_i] = v
|
@@ -515,17 +613,15 @@ class BareTypes
|
|
515
613
|
end
|
516
614
|
|
517
615
|
def encode(msg)
|
518
|
-
raise SchemaMismatch("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
|
616
|
+
raise SchemaMismatch.new("#{msg.inspect} is not part of this enum: #{@intToVal}") if !@valToInt.keys.include?(msg)
|
519
617
|
integerRep = @valToInt[msg]
|
520
618
|
encoded = BareTypes::Uint.new.encode(integerRep)
|
521
619
|
return encoded
|
522
620
|
end
|
523
621
|
|
524
622
|
def decode(msg)
|
525
|
-
|
526
|
-
|
527
|
-
rest = output[:rest]
|
528
|
-
return {value: @intToVal[value], rest: rest}
|
623
|
+
value, rest = BareTypes::Uint.new.decode(msg)
|
624
|
+
return @intToVal[value], rest
|
529
625
|
end
|
530
626
|
end
|
531
627
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bare-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Tracy-Amoroso
|
@@ -10,7 +10,8 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2020-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
13
|
+
description: The first implementation of the BARE (Binary Application Record Encoding)
|
14
|
+
in Ruby. Includes schema parsing and compatibility tests.
|
14
15
|
email: n8@u.northwestern.edu
|
15
16
|
executables: []
|
16
17
|
extensions: []
|
@@ -18,8 +19,10 @@ extra_rdoc_files: []
|
|
18
19
|
files:
|
19
20
|
- "./lib/bare-rb.rb"
|
20
21
|
- "./lib/exceptions.rb"
|
22
|
+
- "./lib/lexer.rb"
|
23
|
+
- "./lib/parser.rb"
|
21
24
|
- "./lib/types.rb"
|
22
|
-
homepage: https://
|
25
|
+
homepage: https://github.com/n8ta/bare-rb
|
23
26
|
licenses:
|
24
27
|
- MIT
|
25
28
|
metadata: {}
|