summaryrefslogtreecommitdiff
path: root/lib/prism/pack.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/prism/pack.rb')
-rw-r--r--lib/prism/pack.rb185
1 files changed, 185 insertions, 0 deletions
diff --git a/lib/prism/pack.rb b/lib/prism/pack.rb
new file mode 100644
index 0000000000..83f5569923
--- /dev/null
+++ b/lib/prism/pack.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+
+module YARP
+ module Pack
+ %i[
+ SPACE
+ COMMENT
+ INTEGER
+ UTF8
+ BER
+ FLOAT
+ STRING_SPACE_PADDED
+ STRING_NULL_PADDED
+ STRING_NULL_TERMINATED
+ STRING_MSB
+ STRING_LSB
+ STRING_HEX_HIGH
+ STRING_HEX_LOW
+ STRING_UU
+ STRING_MIME
+ STRING_BASE64
+ STRING_FIXED
+ STRING_POINTER
+ MOVE
+ BACK
+ NULL
+
+ UNSIGNED
+ SIGNED
+ SIGNED_NA
+
+ AGNOSTIC_ENDIAN
+ LITTLE_ENDIAN
+ BIG_ENDIAN
+ NATIVE_ENDIAN
+ ENDIAN_NA
+
+ SIZE_SHORT
+ SIZE_INT
+ SIZE_LONG
+ SIZE_LONG_LONG
+ SIZE_8
+ SIZE_16
+ SIZE_32
+ SIZE_64
+ SIZE_P
+ SIZE_NA
+
+ LENGTH_FIXED
+ LENGTH_MAX
+ LENGTH_RELATIVE
+ LENGTH_NA
+ ].each do |const|
+ const_set(const, const)
+ end
+
+ class Directive
+ attr_reader :version, :variant, :source, :type, :signed, :endian, :size, :length_type, :length
+
+ def initialize(version, variant, source, type, signed, endian, size, length_type, length)
+ @version = version
+ @variant = variant
+ @source = source
+ @type = type
+ @signed = signed
+ @endian = endian
+ @size = size
+ @length_type = length_type
+ @length = length
+ end
+
+ ENDIAN_DESCRIPTIONS = {
+ AGNOSTIC_ENDIAN: 'agnostic',
+ LITTLE_ENDIAN: 'little-endian (VAX)',
+ BIG_ENDIAN: 'big-endian (network)',
+ NATIVE_ENDIAN: 'native-endian',
+ ENDIAN_NA: 'n/a'
+ }
+
+ SIGNED_DESCRIPTIONS = {
+ UNSIGNED: 'unsigned',
+ SIGNED: 'signed',
+ SIGNED_NA: 'n/a'
+ }
+
+ SIZE_DESCRIPTIONS = {
+ SIZE_SHORT: 'short',
+ SIZE_INT: 'int-width',
+ SIZE_LONG: 'long',
+ SIZE_LONG_LONG: 'long long',
+ SIZE_8: '8-bit',
+ SIZE_16: '16-bit',
+ SIZE_32: '32-bit',
+ SIZE_64: '64-bit',
+ SIZE_P: 'pointer-width'
+ }
+
+ def describe
+ case type
+ when SPACE
+ 'whitespace'
+ when COMMENT
+ 'comment'
+ when INTEGER
+ if size == SIZE_8
+ base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} integer"
+ else
+ base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} integer"
+ end
+ case length_type
+ when LENGTH_FIXED
+ if length > 1
+ base + ", x#{length}"
+ else
+ base
+ end
+ when LENGTH_MAX
+ base + ', as many as possible'
+ end
+ when UTF8
+ 'UTF-8 character'
+ when BER
+ 'BER-compressed integer'
+ when FLOAT
+ "#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float"
+ when STRING_SPACE_PADDED
+ 'arbitrary binary string (space padded)'
+ when STRING_NULL_PADDED
+ 'arbitrary binary string (null padded, count is width)'
+ when STRING_NULL_TERMINATED
+ 'arbitrary binary string (null padded, count is width), except that null is added with *'
+ when STRING_MSB
+ 'bit string (MSB first)'
+ when STRING_LSB
+ 'bit string (LSB first)'
+ when STRING_HEX_HIGH
+ 'hex string (high nibble first)'
+ when STRING_HEX_LOW
+ 'hex string (low nibble first)'
+ when STRING_UU
+ 'UU-encoded string'
+ when STRING_MIME
+ 'quoted printable, MIME encoding'
+ when STRING_BASE64
+ 'base64 encoded string'
+ when STRING_FIXED
+ 'pointer to a structure (fixed-length string)'
+ when STRING_POINTER
+ 'pointer to a null-terminated string'
+ when MOVE
+ 'move to absolute position'
+ when BACK
+ 'back up a byte'
+ when NULL
+ 'null byte'
+ else
+ raise
+ end
+ end
+ end
+
+ class Format
+ attr_reader :directives, :encoding
+
+ def initialize(directives, encoding)
+ @directives = directives
+ @encoding = encoding
+ end
+
+ def describe
+ source_width = directives.map { |d| d.source.inspect.length }.max
+ directive_lines = directives.map do |directive|
+ if directive.type == SPACE
+ source = directive.source.inspect
+ else
+ source = directive.source
+ end
+ " #{source.ljust(source_width)} #{directive.describe}"
+ end
+
+ (['Directives:'] + directive_lines + ['Encoding:', " #{encoding}"]).join("\n")
+ end
+ end
+ end
+end