erlang-etf 1.0.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.
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