pattern.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // -*- js-indent-level: 2 -*-
  2. // Constructing patterns
  3. 'use strict';
  4. function set(values) {
  5. var s = {};
  6. for (var i in values) {
  7. if (!Object.prototype.hasOwnProperty.call(values, i)) continue;
  8. s[values[i]] = 1;
  9. }
  10. return s;
  11. }
  12. // Construct a segment bound to a variable, e.g., from a segment like
  13. // "Len:32/unsigned-big". `specifiers0` is an array.
  14. function variable(name, size, specifiers0) {
  15. var specifiers = set(specifiers0);
  16. var segment = {name: name};
  17. segment.type = type_in(specifiers);
  18. specs(segment, segment.type, specifiers);
  19. segment.size = size_of(segment, segment.type, size, segment.unit);
  20. return segment;
  21. }
  22. module.exports.variable = variable;
  23. module.exports.rest = function() {
  24. return variable('_', true, ['binary']);
  25. }
  26. // Construct a segment with a literal value, e.g., from a segment like
  27. // "206". `specifiers0` is an array.
  28. function value(val, size, specifiers0) {
  29. var specifiers = set(specifiers0);
  30. var segment = {value: val};
  31. segment.type = type_in(specifiers);
  32. // TODO check type v. value ..
  33. specs(segment, segment.type, specifiers);
  34. segment.size = size_of(segment, segment.type, size, segment.unit);
  35. return segment;
  36. }
  37. module.exports.value = value;
  38. // A string can appear as a literal, but it must appear without
  39. // specifiers.
  40. function string(val) {
  41. return {value: val, type: 'string'};
  42. }
  43. module.exports.string = string;
  44. var TYPES = {'integer': 1, 'binary': 1, 'float': 1};
  45. function type_in(specifiers) {
  46. for (var t in specifiers) {
  47. if (!Object.prototype.hasOwnProperty.call(specifiers, t)) continue;
  48. if (TYPES[t]) { return t; }
  49. }
  50. return 'integer';
  51. }
  52. function specs(segment, type, specifiers) {
  53. switch (type) {
  54. case 'integer':
  55. segment.signed = signed_in(specifiers);
  56. // fall through
  57. case 'float':
  58. segment.bigendian = endian_in(specifiers);
  59. // fall through
  60. default:
  61. segment.unit = unit_in(specifiers, segment.type);
  62. }
  63. return segment;
  64. }
  65. function endian_in(specifiers) {
  66. // default is big, but I have chosen true = bigendian
  67. return !specifiers['little'];
  68. }
  69. function signed_in(specifiers) {
  70. // this time I got it right; default is unsigned
  71. return specifiers['signed'];
  72. }
  73. function unit_in(specifiers, type) {
  74. for (var s in specifiers) {
  75. if (!Object.prototype.hasOwnProperty.call(specifiers, s)) continue;
  76. if (s.substr(0, 5) == 'unit:') {
  77. var unit = parseInt(s.substr(5));
  78. // TODO check sane for type
  79. return unit;
  80. }
  81. }
  82. // OK defaults then
  83. switch (type) {
  84. case 'binary':
  85. return 8;
  86. case 'integer':
  87. case 'float':
  88. return 1;
  89. }
  90. }
  91. function size_of(segment, type, size, unit) {
  92. if (size !== undefined && size !== '') {
  93. return size;
  94. }
  95. else {
  96. switch (type) {
  97. case 'integer':
  98. return 8;
  99. case 'float':
  100. return 64;
  101. case 'binary':
  102. return true;
  103. }
  104. }
  105. }