erlang-etf 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +49 -0
  8. data/Rakefile +6 -0
  9. data/erlang-etf.gemspec +30 -0
  10. data/lib/erlang/etf.rb +40 -0
  11. data/lib/erlang/etf/atom.rb +46 -0
  12. data/lib/erlang/etf/atom_utf8.rb +44 -0
  13. data/lib/erlang/etf/bert.rb +74 -0
  14. data/lib/erlang/etf/binary.rb +44 -0
  15. data/lib/erlang/etf/bit_binary.rb +47 -0
  16. data/lib/erlang/etf/export.rb +44 -0
  17. data/lib/erlang/etf/extensions.rb +157 -0
  18. data/lib/erlang/etf/extensions/array.rb +29 -0
  19. data/lib/erlang/etf/extensions/big_decimal.rb +22 -0
  20. data/lib/erlang/etf/extensions/erlang-export.rb +26 -0
  21. data/lib/erlang/etf/extensions/erlang-list.rb +31 -0
  22. data/lib/erlang/etf/extensions/erlang-nil.rb +22 -0
  23. data/lib/erlang/etf/extensions/erlang-pid.rb +22 -0
  24. data/lib/erlang/etf/extensions/erlang-string.rb +22 -0
  25. data/lib/erlang/etf/extensions/erlang-tuple.rb +31 -0
  26. data/lib/erlang/etf/extensions/false_class.rb +28 -0
  27. data/lib/erlang/etf/extensions/float.rb +20 -0
  28. data/lib/erlang/etf/extensions/hash.rb +32 -0
  29. data/lib/erlang/etf/extensions/integer.rb +48 -0
  30. data/lib/erlang/etf/extensions/nil_class.rb +29 -0
  31. data/lib/erlang/etf/extensions/object.rb +24 -0
  32. data/lib/erlang/etf/extensions/regexp.rb +34 -0
  33. data/lib/erlang/etf/extensions/string.rb +35 -0
  34. data/lib/erlang/etf/extensions/symbol.rb +45 -0
  35. data/lib/erlang/etf/extensions/time.rb +29 -0
  36. data/lib/erlang/etf/extensions/true_class.rb +28 -0
  37. data/lib/erlang/etf/float.rb +57 -0
  38. data/lib/erlang/etf/fun.rb +67 -0
  39. data/lib/erlang/etf/integer.rb +29 -0
  40. data/lib/erlang/etf/large_big.rb +53 -0
  41. data/lib/erlang/etf/large_tuple.rb +55 -0
  42. data/lib/erlang/etf/list.rb +50 -0
  43. data/lib/erlang/etf/new_float.rb +33 -0
  44. data/lib/erlang/etf/new_fun.rb +98 -0
  45. data/lib/erlang/etf/new_reference.rb +59 -0
  46. data/lib/erlang/etf/nil.rb +23 -0
  47. data/lib/erlang/etf/pid.rb +45 -0
  48. data/lib/erlang/etf/port.rb +34 -0
  49. data/lib/erlang/etf/reference.rb +41 -0
  50. data/lib/erlang/etf/small_atom.rb +48 -0
  51. data/lib/erlang/etf/small_atom_utf8.rb +44 -0
  52. data/lib/erlang/etf/small_big.rb +59 -0
  53. data/lib/erlang/etf/small_integer.rb +29 -0
  54. data/lib/erlang/etf/small_tuple.rb +56 -0
  55. data/lib/erlang/etf/string.rb +46 -0
  56. data/lib/erlang/etf/term.rb +101 -0
  57. data/lib/erlang/etf/terms.rb +105 -0
  58. data/lib/erlang/etf/version.rb +5 -0
  59. data/spec/erlang/etf/atom_spec.rb +90 -0
  60. data/spec/erlang/etf/atom_utf8_spec.rb +90 -0
  61. data/spec/erlang/etf/binary_spec.rb +90 -0
  62. data/spec/erlang/etf/bit_binary_spec.rb +99 -0
  63. data/spec/erlang/etf/export_spec.rb +58 -0
  64. data/spec/erlang/etf/extensions/array_spec.rb +40 -0
  65. data/spec/erlang/etf/extensions/big_decimal_spec.rb +26 -0
  66. data/spec/erlang/etf/extensions/erlang-export_spec.rb +32 -0
  67. data/spec/erlang/etf/extensions/erlang-list_spec.rb +76 -0
  68. data/spec/erlang/etf/extensions/erlang-nil_spec.rb +24 -0
  69. data/spec/erlang/etf/extensions/erlang-pid_spec.rb +33 -0
  70. data/spec/erlang/etf/extensions/erlang-string_spec.rb +26 -0
  71. data/spec/erlang/etf/extensions/erlang-tuple_spec.rb +56 -0
  72. data/spec/erlang/etf/extensions/false_class_spec.rb +29 -0
  73. data/spec/erlang/etf/extensions/float_spec.rb +24 -0
  74. data/spec/erlang/etf/extensions/hash_spec.rb +90 -0
  75. data/spec/erlang/etf/extensions/integer_spec.rb +259 -0
  76. data/spec/erlang/etf/extensions/nil_class_spec.rb +29 -0
  77. data/spec/erlang/etf/extensions/object_spec.rb +30 -0
  78. data/spec/erlang/etf/extensions/regexp_spec.rb +35 -0
  79. data/spec/erlang/etf/extensions/string_spec.rb +43 -0
  80. data/spec/erlang/etf/extensions/symbol_spec.rb +64 -0
  81. data/spec/erlang/etf/extensions/time_spec.rb +32 -0
  82. data/spec/erlang/etf/extensions/true_class_spec.rb +29 -0
  83. data/spec/erlang/etf/float_spec.rb +92 -0
  84. data/spec/erlang/etf/fun_spec.rb +132 -0
  85. data/spec/erlang/etf/integer_spec.rb +57 -0
  86. data/spec/erlang/etf/large_big_spec.rb +67 -0
  87. data/spec/erlang/etf/large_tuple_spec.rb +119 -0
  88. data/spec/erlang/etf/list_spec.rb +159 -0
  89. data/spec/erlang/etf/new_float_spec.rb +92 -0
  90. data/spec/erlang/etf/new_fun_spec.rb +146 -0
  91. data/spec/erlang/etf/new_reference_spec.rb +60 -0
  92. data/spec/erlang/etf/nil_spec.rb +50 -0
  93. data/spec/erlang/etf/pid_spec.rb +61 -0
  94. data/spec/erlang/etf/port_spec.rb +58 -0
  95. data/spec/erlang/etf/reference_spec.rb +58 -0
  96. data/spec/erlang/etf/small_atom_spec.rb +90 -0
  97. data/spec/erlang/etf/small_atom_utf8_spec.rb +90 -0
  98. data/spec/erlang/etf/small_big_spec.rb +67 -0
  99. data/spec/erlang/etf/small_integer_spec.rb +57 -0
  100. data/spec/erlang/etf/small_tuple_spec.rb +112 -0
  101. data/spec/erlang/etf/string_spec.rb +92 -0
  102. data/spec/erlang/etf/term_spec.rb +27 -0
  103. data/spec/erlang/etf/terms_spec.rb +23 -0
  104. data/spec/erlang/etf_spec.rb +23 -0
  105. data/spec/erlang_spec.rb +77 -0
  106. data/spec/spec_helper.rb +7 -0
  107. metadata +310 -0
@@ -0,0 +1,29 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | 4
6
+ # -- | ---
7
+ # 98 | Int
8
+ #
9
+ # Signed 32 bit integer in big-endian format (i.e. MSB first)
10
+ #
11
+ class Integer
12
+ include Term
13
+
14
+ uint8 :tag, always: Terms::INTEGER_EXT
15
+
16
+ int32be :int
17
+
18
+ finalize
19
+
20
+ def initialize(int)
21
+ @int = int
22
+ end
23
+
24
+ def __ruby_evolve__
25
+ int
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | 4 | 1 | n
6
+ # --- | - | ---- | ---------------
7
+ # 111 | n | Sign | d(0) ... d(n-1)
8
+ #
9
+ # Same as SMALL_BIG_EXT with the difference that the length field
10
+ # is an unsigned 4 byte integer.
11
+ #
12
+ class LargeBig
13
+ include Term
14
+
15
+ uint8 :tag, always: Terms::LARGE_BIG_EXT
16
+
17
+ uint32be :n, default: 0 do
18
+ uint8 :sign, always: -> { (integer >= 0) ? 0 : 1 }
19
+ string :integer
20
+ end
21
+
22
+ undef serialize_integer
23
+ def serialize_integer(buffer)
24
+ start = buffer.bytesize
25
+ buffer << [integer.abs.to_s(2).reverse!].pack(BIN_LSB_PACK)
26
+ self.n = buffer.bytesize - start
27
+ buffer
28
+ end
29
+
30
+ undef after_serialize_n
31
+ def after_serialize_n(buffer)
32
+ buffer[@n_start, BYTES_32] = serialize_n ""
33
+ end
34
+
35
+ deserialize do |buffer|
36
+ deserialize_n(buffer)
37
+ sign, = buffer.read(BYTES_8).unpack(UINT8_PACK)
38
+ self.integer = buffer.read(n).unpack(BIN_LSB_PACK).at(0).reverse!.to_i(2) * ((sign == 0) ? 1 : -1)
39
+ self
40
+ end
41
+
42
+ finalize
43
+
44
+ def initialize(integer)
45
+ @integer = integer
46
+ end
47
+
48
+ def __ruby_evolve__
49
+ integer
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,55 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | 4 | N
6
+ # --- | ----- | --------
7
+ # 105 | Arity | Elements
8
+ #
9
+ # Same as SMALL_TUPLE_EXT with the exception that Arity is an
10
+ # unsigned 4 byte integer in big endian format.
11
+ #
12
+ class LargeTuple
13
+ include Term
14
+
15
+ uint8 :tag, always: Terms::LARGE_TUPLE_EXT
16
+
17
+ uint32be :arity, always: -> { elements.size }
18
+
19
+ term :elements, type: :array
20
+
21
+ deserialize do |buffer|
22
+ arity, = buffer.read(BYTES_32).unpack(UINT32BE_PACK)
23
+ self.elements = []
24
+ arity.times do
25
+ self.elements << Terms.deserialize(buffer)
26
+ end
27
+ self
28
+ end
29
+
30
+ finalize
31
+
32
+ def initialize(elements)
33
+ @elements = elements
34
+ end
35
+
36
+ def serialize_header(buffer)
37
+ serialize_tag(buffer)
38
+ serialize_arity(buffer)
39
+ end
40
+
41
+ def bert?
42
+ elements[0].respond_to?(:atom_name) &&
43
+ elements[0].atom_name == BERT_PREFIX
44
+ end
45
+
46
+ def __ruby_evolve__
47
+ if bert?
48
+ ::Erlang::ETF::BERT.evolve(self)
49
+ else
50
+ ::Erlang::Tuple[*elements.map(&:__ruby_evolve__)]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,50 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | 4 | Len |
6
+ # --- | --- | -------- | ----
7
+ # 108 | Len | Elements | Tail
8
+ #
9
+ # Length is the number of elements that follows in the Elements
10
+ # section. Tail is the final tail of the list; it is NIL_EXT for a
11
+ # proper list, but may be anything type if the list is improper
12
+ # (for instance [a|b]).
13
+ #
14
+ class List
15
+ include Term
16
+
17
+ uint8 :tag, always: Terms::LIST_EXT
18
+
19
+ uint32be :len, always: -> { elements.size }
20
+
21
+ term :elements, type: :array
22
+ term :tail
23
+
24
+ deserialize do |buffer|
25
+ len, = buffer.read(BYTES_32).unpack(UINT32BE_PACK)
26
+ self.elements = []
27
+ len.times do
28
+ self.elements << Terms.deserialize(buffer)
29
+ end
30
+ deserialize_tail(buffer)
31
+ self
32
+ end
33
+
34
+ finalize
35
+
36
+ def initialize(elements, tail = Nil.new)
37
+ @elements = elements
38
+ @tail = tail
39
+ end
40
+
41
+ def improper?
42
+ tail.class != ETF::Nil
43
+ end
44
+
45
+ def __ruby_evolve__
46
+ ::Erlang::List[*elements.map(&:__ruby_evolve__)].tail(tail.__ruby_evolve__)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,33 @@
1
+ require 'bigdecimal'
2
+
3
+ module Erlang
4
+ module ETF
5
+
6
+ #
7
+ # 1 | 8
8
+ # -- | ----------
9
+ # 70 | IEEE Float
10
+ #
11
+ # A float is stored as 8 bytes in big-endian IEEE format.
12
+ #
13
+ # This term is used in minor version 1 of the external format.
14
+ #
15
+ class NewFloat
16
+ include Term
17
+
18
+ uint8 :tag, always: Terms::NEW_FLOAT_EXT
19
+
20
+ doublebe :float
21
+
22
+ finalize
23
+
24
+ def initialize(float)
25
+ @float = float
26
+ end
27
+
28
+ def __ruby_evolve__
29
+ float
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,98 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | 4 | 1 | 16 | 4 | 4 | N1 | N2 | N3 | N4 | N5
6
+ # --- | ---- | ----- | ---- | ----- | ------- | ------ | -------- | ------- | --- | ---------
7
+ # 112 | Size | Arity | Uniq | Index | NumFree | Module | Oldindex | OldUniq | Pid | Free Vars
8
+ #
9
+ # This is the new encoding of internal funs:
10
+ # fun F/A and fun(Arg1,..) -> ... end.
11
+ #
12
+ # Size
13
+ # is the total number of bytes, including the Size field.
14
+ # Arity
15
+ # is the arity of the function implementing the fun.
16
+ # Uniq
17
+ # is the 16 bytes MD5 of the significant parts of the Beam file.
18
+ # Index
19
+ # is an index number. Each fun within a module has an unique
20
+ # index. Index is stored in big-endian byte order.
21
+ # NumFree
22
+ # is the number of free variables.
23
+ # Module
24
+ # is an encoded as an atom, using ATOM_EXT, SMALL_ATOM_EXT or
25
+ # ATOM_CACHE_REF. This is the module that the fun is implemented
26
+ # in.
27
+ # OldIndex
28
+ # is an integer encoded using SMALL_INTEGER_EXT or INTEGER_EXT.
29
+ # It is typically a small index into the module's fun table.
30
+ # OldUniq
31
+ # is an integer encoded using SMALL_INTEGER_EXT or INTEGER_EXT.
32
+ # Uniq is the hash value of the parse tree for the fun.
33
+ # Pid
34
+ # is a process identifier as in PID_EXT. It represents the
35
+ # process in which the fun was created.
36
+ # Free vars
37
+ # is NumFree number of terms, each one encoded according to its
38
+ # type.
39
+ #
40
+ class NewFun
41
+ include Term
42
+
43
+ uint8 :tag, always: Terms::NEW_FUN_EXT
44
+
45
+ uint32be :size, default: 0, inclusive: true do
46
+ uint8 :arity
47
+ string :uniq
48
+ uint32be :index
49
+ uint32be :num_free, always: -> { free_vars.size }
50
+ term :mod
51
+ term :old_index
52
+ term :old_uniq
53
+ term :pid
54
+ term :free_vars, type: :array
55
+ end
56
+
57
+ undef deserialize_uniq
58
+ def deserialize_uniq(buffer)
59
+ self.uniq = buffer.read(16).unpack(UINT8_PACK + '*')
60
+ end
61
+
62
+ undef serialize_uniq
63
+ def serialize_uniq(buffer)
64
+ buffer << uniq.pack(UINT8_PACK + '*')
65
+ end
66
+
67
+ deserialize do |buffer|
68
+ deserialize_size(buffer)
69
+ deserialize_arity(buffer)
70
+ deserialize_uniq(buffer)
71
+ deserialize_index(buffer)
72
+ num_free, = buffer.read(BYTES_32).unpack(UINT32BE_PACK)
73
+ deserialize_mod(buffer)
74
+ deserialize_old_index(buffer)
75
+ deserialize_old_uniq(buffer)
76
+ deserialize_pid(buffer)
77
+ self.free_vars = []
78
+ num_free.times do
79
+ self.free_vars << Terms.deserialize(buffer)
80
+ end
81
+ self
82
+ end
83
+
84
+ finalize
85
+
86
+ def initialize(arity, uniq, index, mod, old_index, old_uniq, pid, free_vars = [])
87
+ self.arity = arity
88
+ self.uniq = uniq
89
+ self.index = index
90
+ self.mod = mod
91
+ self.old_index = old_index
92
+ self.old_uniq = old_uniq
93
+ self.pid = pid
94
+ self.free_vars = free_vars
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,59 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | 2 | N | 1 | N'
6
+ # --- | --- | ---- | -------- | ------
7
+ # 114 | Len | Node | Creation | ID ...
8
+ #
9
+ # Node and Creation are as in REFERENCE_EXT.
10
+ #
11
+ # ID contains a sequence of big-endian unsigned integers (4 bytes
12
+ # each, so N' is a multiple of 4), but should be regarded as
13
+ # uninterpreted data.
14
+ #
15
+ # N' = 4 * Len.
16
+ #
17
+ # In the first word (four bytes) of ID, only 18 bits are
18
+ # significant, the rest should be 0. In Creation, only 2 bits are
19
+ # significant, the rest should be 0.
20
+ #
21
+ # NEW_REFERENCE_EXT was introduced with distribution version 4. In
22
+ # version 4, N' should be at most 12.
23
+ #
24
+ # See REFERENCE_EXT).
25
+ #
26
+ class NewReference
27
+ include Term
28
+
29
+ uint8 :tag, always: Terms::NEW_REFERENCE_EXT
30
+
31
+ uint16be :len, always: -> { ids.size }
32
+
33
+ term :node
34
+
35
+ int8 :creation, maximum: (1 << 2) - 1
36
+
37
+ uint32be :ids, type: :array, default: []
38
+
39
+ deserialize do |buffer|
40
+ len, = buffer.read(BYTES_16).unpack(UINT16BE_PACK)
41
+ deserialize_node(buffer)
42
+ deserialize_creation(buffer)
43
+ self.ids = []
44
+ len.times do
45
+ self.ids << buffer.read(BYTES_32).unpack(UINT32BE_PACK).at(0)
46
+ end
47
+ self
48
+ end
49
+
50
+ finalize
51
+
52
+ def initialize(node, creation, ids = [])
53
+ @node = node
54
+ @creation = creation
55
+ @ids = ids
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1
6
+ # ---
7
+ # 106
8
+ #
9
+ # The representation for an empty list, i.e. the Erlang syntax [].
10
+ #
11
+ class Nil
12
+ include Term
13
+
14
+ uint8 :tag, always: Terms::NIL_EXT
15
+
16
+ finalize
17
+
18
+ def __ruby_evolve__
19
+ []
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ module Erlang
2
+ module ETF
3
+
4
+ #
5
+ # 1 | N | 4 | 4 | 1
6
+ # --- | ---- | -- | ------ | --------
7
+ # 103 | Node | ID | Serial | Creation
8
+ #
9
+ # Encode a process identifier object (obtained from spawn/3 or
10
+ # friends). The ID and Creation fields works just like in
11
+ # REFERENCE_EXT, while the Serial field is used to improve safety.
12
+ # In ID, only 15 bits are significant; the rest should be 0.
13
+ #
14
+ class Pid
15
+ include Term
16
+
17
+ uint8 :tag, always: Terms::PID_EXT
18
+
19
+ term :node
20
+
21
+ uint32be :id, maximum: (1 << 15) - 1
22
+ uint32be :serial, maximum: (1 << 13) - 1
23
+
24
+ int8 :creation, maximum: (1 << 2) - 1
25
+
26
+ finalize
27
+
28
+ def initialize(node, id, serial, creation)
29
+ @node = node
30
+ @id = id
31
+ @serial = serial
32
+ @creation = creation
33
+ end
34
+
35
+ def __ruby_evolve__
36
+ ::Erlang::Pid.new(
37
+ node.__ruby_evolve__,
38
+ id,
39
+ serial,
40
+ creation
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end