@k67/kaitai-struct-ts 0.2.0 → 0.5.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.
package/dist/index.js CHANGED
@@ -866,17 +866,23 @@ var Context = class _Context {
866
866
  * @param _io - Binary stream being read
867
867
  * @param _root - Root object of the parse tree
868
868
  * @param _parent - Parent object (optional)
869
+ * @param enums - Enum definitions from schema (optional)
869
870
  */
870
- constructor(_io, _root = null, _parent = null) {
871
+ constructor(_io, _root = null, _parent = null, enums) {
871
872
  this._io = _io;
872
873
  this._root = _root;
873
874
  /** Stack of parent objects */
874
875
  this.parentStack = [];
875
876
  /** Current object being parsed */
876
877
  this._current = {};
878
+ /** Enum definitions from schema */
879
+ this._enums = {};
877
880
  if (_parent !== null) {
878
881
  this.parentStack.push(_parent);
879
882
  }
883
+ if (enums) {
884
+ this._enums = enums;
885
+ }
880
886
  }
881
887
  /**
882
888
  * Get the current I/O stream.
@@ -973,6 +979,36 @@ var Context = class _Context {
973
979
  set(name, value) {
974
980
  this._current[name] = value;
975
981
  }
982
+ /**
983
+ * Get enum value by name.
984
+ * Used for enum access in expressions (EnumName::value).
985
+ *
986
+ * @param enumName - Name of the enum
987
+ * @param valueName - Name of the enum value
988
+ * @returns Enum value (number) or undefined
989
+ */
990
+ getEnumValue(enumName, valueName) {
991
+ const enumDef = this._enums[enumName];
992
+ if (!enumDef) {
993
+ return void 0;
994
+ }
995
+ for (const [key, value] of Object.entries(enumDef)) {
996
+ if (value === valueName) {
997
+ const numKey = Number(key);
998
+ return isNaN(numKey) ? key : numKey;
999
+ }
1000
+ }
1001
+ return void 0;
1002
+ }
1003
+ /**
1004
+ * Check if an enum exists.
1005
+ *
1006
+ * @param enumName - Name of the enum
1007
+ * @returns True if enum exists
1008
+ */
1009
+ hasEnum(enumName) {
1010
+ return enumName in this._enums;
1011
+ }
976
1012
  /**
977
1013
  * Create a child context for nested parsing.
978
1014
  * The current object becomes the parent in the child context.
@@ -984,7 +1020,8 @@ var Context = class _Context {
984
1020
  const childContext = new _Context(
985
1021
  stream || this._io,
986
1022
  this._root || this._current,
987
- this._current
1023
+ this._current,
1024
+ this._enums
988
1025
  );
989
1026
  return childContext;
990
1027
  }
@@ -995,13 +1032,917 @@ var Context = class _Context {
995
1032
  * @returns Cloned context
996
1033
  */
997
1034
  clone() {
998
- const cloned = new _Context(this._io, this._root, this.parent);
1035
+ const cloned = new _Context(this._io, this._root, this.parent, this._enums);
999
1036
  cloned._current = { ...this._current };
1000
1037
  cloned.parentStack = [...this.parentStack];
1001
1038
  return cloned;
1002
1039
  }
1003
1040
  };
1004
1041
 
1042
+ // src/expression/Token.ts
1043
+ function createToken(type, value = null, position = 0) {
1044
+ return { type, value, position };
1045
+ }
1046
+
1047
+ // src/expression/Lexer.ts
1048
+ var Lexer = class {
1049
+ /**
1050
+ * Create a new lexer.
1051
+ *
1052
+ * @param input - Expression string to tokenize
1053
+ */
1054
+ constructor(input) {
1055
+ this.position = 0;
1056
+ this.current = null;
1057
+ this.input = input;
1058
+ this.current = input.length > 0 ? input[0] : null;
1059
+ }
1060
+ /**
1061
+ * Tokenize the entire input string.
1062
+ *
1063
+ * @returns Array of tokens
1064
+ * @throws {ParseError} If invalid syntax is encountered
1065
+ */
1066
+ tokenize() {
1067
+ const tokens = [];
1068
+ while (this.current !== null) {
1069
+ if (this.isWhitespace(this.current)) {
1070
+ this.skipWhitespace();
1071
+ continue;
1072
+ }
1073
+ if (this.isDigit(this.current)) {
1074
+ tokens.push(this.readNumber());
1075
+ continue;
1076
+ }
1077
+ if (this.isIdentifierStart(this.current)) {
1078
+ tokens.push(this.readIdentifierOrKeyword());
1079
+ continue;
1080
+ }
1081
+ if (this.current === '"' || this.current === "'") {
1082
+ tokens.push(this.readString());
1083
+ continue;
1084
+ }
1085
+ const token = this.readOperator();
1086
+ if (token) {
1087
+ tokens.push(token);
1088
+ continue;
1089
+ }
1090
+ throw new ParseError(
1091
+ `Unexpected character: ${this.current}`,
1092
+ this.position
1093
+ );
1094
+ }
1095
+ tokens.push(createToken("EOF" /* EOF */, null, this.position));
1096
+ return tokens;
1097
+ }
1098
+ /**
1099
+ * Advance to the next character.
1100
+ * @private
1101
+ */
1102
+ advance() {
1103
+ this.position++;
1104
+ this.current = this.position < this.input.length ? this.input[this.position] : null;
1105
+ }
1106
+ /**
1107
+ * Peek at the next character without advancing.
1108
+ * @private
1109
+ */
1110
+ peek(offset = 1) {
1111
+ const pos = this.position + offset;
1112
+ return pos < this.input.length ? this.input[pos] : null;
1113
+ }
1114
+ /**
1115
+ * Check if character is whitespace.
1116
+ * @private
1117
+ */
1118
+ isWhitespace(char) {
1119
+ return /\s/.test(char);
1120
+ }
1121
+ /**
1122
+ * Check if character is a digit.
1123
+ * @private
1124
+ */
1125
+ isDigit(char) {
1126
+ return /[0-9]/.test(char);
1127
+ }
1128
+ /**
1129
+ * Check if character can start an identifier.
1130
+ * @private
1131
+ */
1132
+ isIdentifierStart(char) {
1133
+ return /[a-zA-Z_]/.test(char);
1134
+ }
1135
+ /**
1136
+ * Check if character can be part of an identifier.
1137
+ * @private
1138
+ */
1139
+ isIdentifierPart(char) {
1140
+ return /[a-zA-Z0-9_]/.test(char);
1141
+ }
1142
+ /**
1143
+ * Skip whitespace characters.
1144
+ * @private
1145
+ */
1146
+ skipWhitespace() {
1147
+ while (this.current !== null && this.isWhitespace(this.current)) {
1148
+ this.advance();
1149
+ }
1150
+ }
1151
+ /**
1152
+ * Read a number token.
1153
+ * @private
1154
+ */
1155
+ readNumber() {
1156
+ const start = this.position;
1157
+ let value = "";
1158
+ if (this.current === "0" && this.peek() === "x") {
1159
+ value += this.current;
1160
+ this.advance();
1161
+ value += this.current;
1162
+ this.advance();
1163
+ while (this.current !== null && /[0-9a-fA-F]/.test(this.current)) {
1164
+ value += this.current;
1165
+ this.advance();
1166
+ }
1167
+ return createToken("NUMBER" /* NUMBER */, parseInt(value, 16), start);
1168
+ }
1169
+ while (this.current !== null && this.isDigit(this.current)) {
1170
+ value += this.current;
1171
+ this.advance();
1172
+ }
1173
+ if (this.current === "." && this.peek() && this.isDigit(this.peek())) {
1174
+ value += this.current;
1175
+ this.advance();
1176
+ while (this.current !== null && this.isDigit(this.current)) {
1177
+ value += this.current;
1178
+ this.advance();
1179
+ }
1180
+ return createToken("NUMBER" /* NUMBER */, parseFloat(value), start);
1181
+ }
1182
+ return createToken("NUMBER" /* NUMBER */, parseInt(value, 10), start);
1183
+ }
1184
+ /**
1185
+ * Read an identifier or keyword token.
1186
+ * @private
1187
+ */
1188
+ readIdentifierOrKeyword() {
1189
+ const start = this.position;
1190
+ let value = "";
1191
+ while (this.current !== null && this.isIdentifierPart(this.current)) {
1192
+ value += this.current;
1193
+ this.advance();
1194
+ }
1195
+ switch (value) {
1196
+ case "true":
1197
+ return createToken("BOOLEAN" /* BOOLEAN */, true, start);
1198
+ case "false":
1199
+ return createToken("BOOLEAN" /* BOOLEAN */, false, start);
1200
+ case "and":
1201
+ return createToken("AND" /* AND */, value, start);
1202
+ case "or":
1203
+ return createToken("OR" /* OR */, value, start);
1204
+ case "not":
1205
+ return createToken("NOT" /* NOT */, value, start);
1206
+ default:
1207
+ return createToken("IDENTIFIER" /* IDENTIFIER */, value, start);
1208
+ }
1209
+ }
1210
+ /**
1211
+ * Read a string token.
1212
+ * @private
1213
+ */
1214
+ readString() {
1215
+ const start = this.position;
1216
+ const quote = this.current;
1217
+ let value = "";
1218
+ this.advance();
1219
+ while (this.current !== null && this.current !== quote) {
1220
+ if (this.current === "\\") {
1221
+ this.advance();
1222
+ if (this.current === null) {
1223
+ throw new ParseError("Unterminated string", start);
1224
+ }
1225
+ const ch = this.current;
1226
+ if (ch === "n") {
1227
+ value += "\n";
1228
+ } else if (ch === "t") {
1229
+ value += " ";
1230
+ } else if (ch === "r") {
1231
+ value += "\r";
1232
+ } else if (ch === "\\") {
1233
+ value += "\\";
1234
+ } else if (ch === '"') {
1235
+ value += '"';
1236
+ } else if (ch === "'") {
1237
+ value += "'";
1238
+ } else {
1239
+ value += ch;
1240
+ }
1241
+ } else {
1242
+ value += this.current;
1243
+ }
1244
+ this.advance();
1245
+ }
1246
+ if (this.current === null) {
1247
+ throw new ParseError("Unterminated string", start);
1248
+ }
1249
+ this.advance();
1250
+ return createToken("STRING" /* STRING */, value, start);
1251
+ }
1252
+ /**
1253
+ * Read an operator or punctuation token.
1254
+ * @private
1255
+ */
1256
+ readOperator() {
1257
+ const start = this.position;
1258
+ const char = this.current;
1259
+ switch (char) {
1260
+ case "+":
1261
+ this.advance();
1262
+ return createToken("PLUS" /* PLUS */, char, start);
1263
+ case "-":
1264
+ this.advance();
1265
+ return createToken("MINUS" /* MINUS */, char, start);
1266
+ case "*":
1267
+ this.advance();
1268
+ return createToken("STAR" /* STAR */, char, start);
1269
+ case "/":
1270
+ this.advance();
1271
+ return createToken("SLASH" /* SLASH */, char, start);
1272
+ case "%":
1273
+ this.advance();
1274
+ return createToken("PERCENT" /* PERCENT */, char, start);
1275
+ case "<":
1276
+ this.advance();
1277
+ if (this.current === "=") {
1278
+ this.advance();
1279
+ return createToken("LE" /* LE */, "<=", start);
1280
+ } else if (this.current === "<") {
1281
+ this.advance();
1282
+ return createToken("LSHIFT" /* LSHIFT */, "<<", start);
1283
+ }
1284
+ return createToken("LT" /* LT */, "<", start);
1285
+ case ">":
1286
+ this.advance();
1287
+ if (this.current === "=") {
1288
+ this.advance();
1289
+ return createToken("GE" /* GE */, ">=", start);
1290
+ } else if (this.current === ">") {
1291
+ this.advance();
1292
+ return createToken("RSHIFT" /* RSHIFT */, ">>", start);
1293
+ }
1294
+ return createToken("GT" /* GT */, ">", start);
1295
+ case "=":
1296
+ this.advance();
1297
+ if (this.current === "=") {
1298
+ this.advance();
1299
+ return createToken("EQ" /* EQ */, "==", start);
1300
+ }
1301
+ throw new ParseError("Expected == for equality", start);
1302
+ case "!":
1303
+ this.advance();
1304
+ if (this.current === "=") {
1305
+ this.advance();
1306
+ return createToken("NE" /* NE */, "!=", start);
1307
+ }
1308
+ throw new ParseError("Expected != for inequality", start);
1309
+ case "&":
1310
+ this.advance();
1311
+ return createToken("AMPERSAND" /* AMPERSAND */, char, start);
1312
+ case "|":
1313
+ this.advance();
1314
+ return createToken("PIPE" /* PIPE */, char, start);
1315
+ case "^":
1316
+ this.advance();
1317
+ return createToken("CARET" /* CARET */, char, start);
1318
+ case "?":
1319
+ this.advance();
1320
+ return createToken("QUESTION" /* QUESTION */, char, start);
1321
+ case ":":
1322
+ this.advance();
1323
+ if (this.current === ":") {
1324
+ this.advance();
1325
+ return createToken("DOUBLE_COLON" /* DOUBLE_COLON */, "::", start);
1326
+ }
1327
+ return createToken("COLON" /* COLON */, char, start);
1328
+ case "(":
1329
+ this.advance();
1330
+ return createToken("LPAREN" /* LPAREN */, char, start);
1331
+ case ")":
1332
+ this.advance();
1333
+ return createToken("RPAREN" /* RPAREN */, char, start);
1334
+ case "[":
1335
+ this.advance();
1336
+ return createToken("LBRACKET" /* LBRACKET */, char, start);
1337
+ case "]":
1338
+ this.advance();
1339
+ return createToken("RBRACKET" /* RBRACKET */, char, start);
1340
+ case ".":
1341
+ this.advance();
1342
+ return createToken("DOT" /* DOT */, char, start);
1343
+ case ",":
1344
+ this.advance();
1345
+ return createToken("COMMA" /* COMMA */, char, start);
1346
+ default:
1347
+ return null;
1348
+ }
1349
+ }
1350
+ };
1351
+
1352
+ // src/expression/AST.ts
1353
+ function createLiteral(value) {
1354
+ return { kind: "Literal", value };
1355
+ }
1356
+ function createIdentifier(name) {
1357
+ return { kind: "Identifier", name };
1358
+ }
1359
+ function createBinaryOp(operator, left, right) {
1360
+ return { kind: "BinaryOp", operator, left, right };
1361
+ }
1362
+ function createUnaryOp(operator, operand) {
1363
+ return { kind: "UnaryOp", operator, operand };
1364
+ }
1365
+ function createTernary(condition, ifTrue, ifFalse) {
1366
+ return { kind: "Ternary", condition, ifTrue, ifFalse };
1367
+ }
1368
+ function createMemberAccess(object, property) {
1369
+ return { kind: "MemberAccess", object, property };
1370
+ }
1371
+ function createIndexAccess(object, index) {
1372
+ return { kind: "IndexAccess", object, index };
1373
+ }
1374
+ function createMethodCall(object, method, args) {
1375
+ return { kind: "MethodCall", object, method, args };
1376
+ }
1377
+ function createEnumAccess(enumName, value) {
1378
+ return { kind: "EnumAccess", enumName, value };
1379
+ }
1380
+
1381
+ // src/expression/Parser.ts
1382
+ var ExpressionParser = class {
1383
+ /**
1384
+ * Create a new expression parser.
1385
+ *
1386
+ * @param tokens - Array of tokens to parse
1387
+ */
1388
+ constructor(tokens) {
1389
+ this.position = 0;
1390
+ this.tokens = tokens;
1391
+ }
1392
+ /**
1393
+ * Parse the tokens into an AST.
1394
+ *
1395
+ * @returns Root AST node
1396
+ * @throws {ParseError} If invalid syntax is encountered
1397
+ */
1398
+ parse() {
1399
+ const expr = this.parseTernary();
1400
+ if (!this.isAtEnd()) {
1401
+ throw new ParseError(
1402
+ `Unexpected token: ${this.current().type}`,
1403
+ this.current().position
1404
+ );
1405
+ }
1406
+ return expr;
1407
+ }
1408
+ /**
1409
+ * Get the current token.
1410
+ * @private
1411
+ */
1412
+ current() {
1413
+ return this.tokens[this.position];
1414
+ }
1415
+ /**
1416
+ * Check if we're at the end of tokens.
1417
+ * @private
1418
+ */
1419
+ isAtEnd() {
1420
+ return this.current().type === "EOF" /* EOF */;
1421
+ }
1422
+ /**
1423
+ * Advance to the next token.
1424
+ * @private
1425
+ */
1426
+ advance() {
1427
+ if (!this.isAtEnd()) {
1428
+ this.position++;
1429
+ }
1430
+ return this.tokens[this.position - 1];
1431
+ }
1432
+ /**
1433
+ * Check if current token matches any of the given types.
1434
+ * @private
1435
+ */
1436
+ match(...types) {
1437
+ for (const type of types) {
1438
+ if (this.current().type === type) {
1439
+ this.advance();
1440
+ return true;
1441
+ }
1442
+ }
1443
+ return false;
1444
+ }
1445
+ /**
1446
+ * Expect a specific token type and advance.
1447
+ * @private
1448
+ */
1449
+ expect(type, message) {
1450
+ if (this.current().type !== type) {
1451
+ throw new ParseError(message, this.current().position);
1452
+ }
1453
+ return this.advance();
1454
+ }
1455
+ /**
1456
+ * Parse ternary conditional (lowest precedence).
1457
+ * condition ? ifTrue : ifFalse
1458
+ * @private
1459
+ */
1460
+ parseTernary() {
1461
+ let expr = this.parseLogicalOr();
1462
+ if (this.match("QUESTION" /* QUESTION */)) {
1463
+ const ifTrue = this.parseTernary();
1464
+ this.expect("COLON" /* COLON */, "Expected : in ternary expression");
1465
+ const ifFalse = this.parseTernary();
1466
+ return createTernary(expr, ifTrue, ifFalse);
1467
+ }
1468
+ return expr;
1469
+ }
1470
+ /**
1471
+ * Parse logical OR.
1472
+ * @private
1473
+ */
1474
+ parseLogicalOr() {
1475
+ let left = this.parseLogicalAnd();
1476
+ while (this.match("OR" /* OR */)) {
1477
+ const operator = "or";
1478
+ const right = this.parseLogicalAnd();
1479
+ left = createBinaryOp(operator, left, right);
1480
+ }
1481
+ return left;
1482
+ }
1483
+ /**
1484
+ * Parse logical AND.
1485
+ * @private
1486
+ */
1487
+ parseLogicalAnd() {
1488
+ let left = this.parseBitwiseOr();
1489
+ while (this.match("AND" /* AND */)) {
1490
+ const operator = "and";
1491
+ const right = this.parseBitwiseOr();
1492
+ left = createBinaryOp(operator, left, right);
1493
+ }
1494
+ return left;
1495
+ }
1496
+ /**
1497
+ * Parse bitwise OR.
1498
+ * @private
1499
+ */
1500
+ parseBitwiseOr() {
1501
+ let left = this.parseBitwiseXor();
1502
+ while (this.match("PIPE" /* PIPE */)) {
1503
+ const operator = "|";
1504
+ const right = this.parseBitwiseXor();
1505
+ left = createBinaryOp(operator, left, right);
1506
+ }
1507
+ return left;
1508
+ }
1509
+ /**
1510
+ * Parse bitwise XOR.
1511
+ * @private
1512
+ */
1513
+ parseBitwiseXor() {
1514
+ let left = this.parseBitwiseAnd();
1515
+ while (this.match("CARET" /* CARET */)) {
1516
+ const operator = "^";
1517
+ const right = this.parseBitwiseAnd();
1518
+ left = createBinaryOp(operator, left, right);
1519
+ }
1520
+ return left;
1521
+ }
1522
+ /**
1523
+ * Parse bitwise AND.
1524
+ * @private
1525
+ */
1526
+ parseBitwiseAnd() {
1527
+ let left = this.parseEquality();
1528
+ while (this.match("AMPERSAND" /* AMPERSAND */)) {
1529
+ const operator = "&";
1530
+ const right = this.parseEquality();
1531
+ left = createBinaryOp(operator, left, right);
1532
+ }
1533
+ return left;
1534
+ }
1535
+ /**
1536
+ * Parse equality operators (==, !=).
1537
+ * @private
1538
+ */
1539
+ parseEquality() {
1540
+ let left = this.parseRelational();
1541
+ while (this.match("EQ" /* EQ */, "NE" /* NE */)) {
1542
+ const operator = this.tokens[this.position - 1].value;
1543
+ const right = this.parseRelational();
1544
+ left = createBinaryOp(operator, left, right);
1545
+ }
1546
+ return left;
1547
+ }
1548
+ /**
1549
+ * Parse relational operators (<, <=, >, >=).
1550
+ * @private
1551
+ */
1552
+ parseRelational() {
1553
+ let left = this.parseBitShift();
1554
+ while (this.match("LT" /* LT */, "LE" /* LE */, "GT" /* GT */, "GE" /* GE */)) {
1555
+ const operator = this.tokens[this.position - 1].value;
1556
+ const right = this.parseBitShift();
1557
+ left = createBinaryOp(operator, left, right);
1558
+ }
1559
+ return left;
1560
+ }
1561
+ /**
1562
+ * Parse bit shift operators (<<, >>).
1563
+ * @private
1564
+ */
1565
+ parseBitShift() {
1566
+ let left = this.parseAdditive();
1567
+ while (this.match("LSHIFT" /* LSHIFT */, "RSHIFT" /* RSHIFT */)) {
1568
+ const operator = this.tokens[this.position - 1].value;
1569
+ const right = this.parseAdditive();
1570
+ left = createBinaryOp(operator, left, right);
1571
+ }
1572
+ return left;
1573
+ }
1574
+ /**
1575
+ * Parse additive operators (+, -).
1576
+ * @private
1577
+ */
1578
+ parseAdditive() {
1579
+ let left = this.parseMultiplicative();
1580
+ while (this.match("PLUS" /* PLUS */, "MINUS" /* MINUS */)) {
1581
+ const operator = this.tokens[this.position - 1].value;
1582
+ const right = this.parseMultiplicative();
1583
+ left = createBinaryOp(operator, left, right);
1584
+ }
1585
+ return left;
1586
+ }
1587
+ /**
1588
+ * Parse multiplicative operators (*, /, %).
1589
+ * @private
1590
+ */
1591
+ parseMultiplicative() {
1592
+ let left = this.parseUnary();
1593
+ while (this.match("STAR" /* STAR */, "SLASH" /* SLASH */, "PERCENT" /* PERCENT */)) {
1594
+ const operator = this.tokens[this.position - 1].value;
1595
+ const right = this.parseUnary();
1596
+ left = createBinaryOp(operator, left, right);
1597
+ }
1598
+ return left;
1599
+ }
1600
+ /**
1601
+ * Parse unary operators (-, not).
1602
+ * @private
1603
+ */
1604
+ parseUnary() {
1605
+ if (this.match("MINUS" /* MINUS */, "NOT" /* NOT */)) {
1606
+ const operator = this.tokens[this.position - 1].value;
1607
+ const operand = this.parseUnary();
1608
+ return createUnaryOp(operator, operand);
1609
+ }
1610
+ return this.parsePostfix();
1611
+ }
1612
+ /**
1613
+ * Parse postfix operators (., [], ()).
1614
+ * @private
1615
+ */
1616
+ parsePostfix() {
1617
+ let expr = this.parsePrimary();
1618
+ while (true) {
1619
+ if (this.match("DOT" /* DOT */)) {
1620
+ const property = this.expect(
1621
+ "IDENTIFIER" /* IDENTIFIER */,
1622
+ "Expected property name after ."
1623
+ );
1624
+ expr = createMemberAccess(expr, property.value);
1625
+ } else if (this.match("LBRACKET" /* LBRACKET */)) {
1626
+ const index = this.parseTernary();
1627
+ this.expect("RBRACKET" /* RBRACKET */, "Expected ] after array index");
1628
+ expr = createIndexAccess(expr, index);
1629
+ } else if (this.current().type === "LPAREN" /* LPAREN */) {
1630
+ if (expr.kind === "MemberAccess") {
1631
+ this.advance();
1632
+ const args = [];
1633
+ if (this.current().type !== "RPAREN" /* RPAREN */) {
1634
+ args.push(this.parseTernary());
1635
+ while (this.match("COMMA" /* COMMA */)) {
1636
+ args.push(this.parseTernary());
1637
+ }
1638
+ }
1639
+ this.expect("RPAREN" /* RPAREN */, "Expected ) after arguments");
1640
+ const memberExpr = expr;
1641
+ expr = createMethodCall(memberExpr.object, memberExpr.property, args);
1642
+ } else {
1643
+ break;
1644
+ }
1645
+ } else {
1646
+ break;
1647
+ }
1648
+ }
1649
+ return expr;
1650
+ }
1651
+ /**
1652
+ * Parse primary expressions (literals, identifiers, grouping).
1653
+ * @private
1654
+ */
1655
+ parsePrimary() {
1656
+ if (this.match("NUMBER" /* NUMBER */, "STRING" /* STRING */, "BOOLEAN" /* BOOLEAN */)) {
1657
+ const token = this.tokens[this.position - 1];
1658
+ return createLiteral(token.value);
1659
+ }
1660
+ if (this.match("IDENTIFIER" /* IDENTIFIER */)) {
1661
+ const name = this.tokens[this.position - 1].value;
1662
+ if (this.match("DOUBLE_COLON" /* DOUBLE_COLON */)) {
1663
+ const value = this.expect(
1664
+ "IDENTIFIER" /* IDENTIFIER */,
1665
+ "Expected enum value after ::"
1666
+ );
1667
+ return createEnumAccess(name, value.value);
1668
+ }
1669
+ return createIdentifier(name);
1670
+ }
1671
+ if (this.match("LPAREN" /* LPAREN */)) {
1672
+ const expr = this.parseTernary();
1673
+ this.expect("RPAREN" /* RPAREN */, "Expected ) after expression");
1674
+ return expr;
1675
+ }
1676
+ throw new ParseError(
1677
+ `Unexpected token: ${this.current().type}`,
1678
+ this.current().position
1679
+ );
1680
+ }
1681
+ };
1682
+
1683
+ // src/expression/Evaluator.ts
1684
+ var Evaluator = class {
1685
+ /**
1686
+ * Evaluate an AST node in the given context.
1687
+ *
1688
+ * @param node - AST node to evaluate
1689
+ * @param context - Execution context
1690
+ * @returns Evaluated value
1691
+ * @throws {ParseError} If evaluation fails
1692
+ */
1693
+ evaluate(node, context) {
1694
+ const n = node;
1695
+ switch (node.kind) {
1696
+ case "Literal":
1697
+ return n.value;
1698
+ case "Identifier":
1699
+ return this.evaluateIdentifier(n.name, context);
1700
+ case "BinaryOp":
1701
+ return this.evaluateBinaryOp(n.operator, n.left, n.right, context);
1702
+ case "UnaryOp":
1703
+ return this.evaluateUnaryOp(n.operator, n.operand, context);
1704
+ case "Ternary":
1705
+ return this.evaluateTernary(n.condition, n.ifTrue, n.ifFalse, context);
1706
+ case "MemberAccess":
1707
+ return this.evaluateMemberAccess(n.object, n.property, context);
1708
+ case "IndexAccess":
1709
+ return this.evaluateIndexAccess(n.object, n.index, context);
1710
+ case "MethodCall":
1711
+ return this.evaluateMethodCall(n.object, n.method, n.args, context);
1712
+ case "EnumAccess":
1713
+ return this.evaluateEnumAccess(n.enumName, n.value, context);
1714
+ default:
1715
+ throw new ParseError(`Unknown AST node kind: ${node.kind}`);
1716
+ }
1717
+ }
1718
+ /**
1719
+ * Evaluate an identifier.
1720
+ * @private
1721
+ */
1722
+ evaluateIdentifier(name, context) {
1723
+ return context.resolve(name);
1724
+ }
1725
+ /**
1726
+ * Evaluate a binary operation.
1727
+ * @private
1728
+ */
1729
+ evaluateBinaryOp(operator, left, right, context) {
1730
+ const leftVal = this.evaluate(left, context);
1731
+ const rightVal = this.evaluate(right, context);
1732
+ switch (operator) {
1733
+ // Arithmetic
1734
+ case "+":
1735
+ return this.add(leftVal, rightVal);
1736
+ case "-":
1737
+ return this.toNumber(leftVal) - this.toNumber(rightVal);
1738
+ case "*":
1739
+ return this.toNumber(leftVal) * this.toNumber(rightVal);
1740
+ case "/":
1741
+ return this.toNumber(leftVal) / this.toNumber(rightVal);
1742
+ case "%":
1743
+ return this.modulo(this.toNumber(leftVal), this.toNumber(rightVal));
1744
+ // Comparison
1745
+ case "<":
1746
+ return this.compare(leftVal, rightVal) < 0;
1747
+ case "<=":
1748
+ return this.compare(leftVal, rightVal) <= 0;
1749
+ case ">":
1750
+ return this.compare(leftVal, rightVal) > 0;
1751
+ case ">=":
1752
+ return this.compare(leftVal, rightVal) >= 0;
1753
+ case "==":
1754
+ return this.equals(leftVal, rightVal);
1755
+ case "!=":
1756
+ return !this.equals(leftVal, rightVal);
1757
+ // Bitwise
1758
+ case "<<":
1759
+ return this.toInt(leftVal) << this.toInt(rightVal);
1760
+ case ">>":
1761
+ return this.toInt(leftVal) >> this.toInt(rightVal);
1762
+ case "&":
1763
+ return this.toInt(leftVal) & this.toInt(rightVal);
1764
+ case "|":
1765
+ return this.toInt(leftVal) | this.toInt(rightVal);
1766
+ case "^":
1767
+ return this.toInt(leftVal) ^ this.toInt(rightVal);
1768
+ // Logical
1769
+ case "and":
1770
+ return this.toBoolean(leftVal) && this.toBoolean(rightVal);
1771
+ case "or":
1772
+ return this.toBoolean(leftVal) || this.toBoolean(rightVal);
1773
+ default:
1774
+ throw new ParseError(`Unknown binary operator: ${operator}`);
1775
+ }
1776
+ }
1777
+ /**
1778
+ * Evaluate a unary operation.
1779
+ * @private
1780
+ */
1781
+ evaluateUnaryOp(operator, operand, context) {
1782
+ const value = this.evaluate(operand, context);
1783
+ switch (operator) {
1784
+ case "-":
1785
+ return -this.toNumber(value);
1786
+ case "not":
1787
+ return !this.toBoolean(value);
1788
+ default:
1789
+ throw new ParseError(`Unknown unary operator: ${operator}`);
1790
+ }
1791
+ }
1792
+ /**
1793
+ * Evaluate a ternary conditional.
1794
+ * @private
1795
+ */
1796
+ evaluateTernary(condition, ifTrue, ifFalse, context) {
1797
+ const condValue = this.evaluate(condition, context);
1798
+ return this.toBoolean(condValue) ? this.evaluate(ifTrue, context) : this.evaluate(ifFalse, context);
1799
+ }
1800
+ /**
1801
+ * Evaluate member access (object.property).
1802
+ * @private
1803
+ */
1804
+ evaluateMemberAccess(object, property, context) {
1805
+ const obj = this.evaluate(object, context);
1806
+ if (obj === null || obj === void 0) {
1807
+ throw new ParseError(
1808
+ `Cannot access property ${property} of null/undefined`
1809
+ );
1810
+ }
1811
+ if (typeof obj === "object") {
1812
+ return obj[property];
1813
+ }
1814
+ throw new ParseError(`Cannot access property ${property} of non-object`);
1815
+ }
1816
+ /**
1817
+ * Evaluate index access (array[index]).
1818
+ * @private
1819
+ */
1820
+ evaluateIndexAccess(object, index, context) {
1821
+ const obj = this.evaluate(object, context);
1822
+ const idx = this.evaluate(index, context);
1823
+ if (Array.isArray(obj)) {
1824
+ const numIdx = this.toInt(idx);
1825
+ return obj[numIdx];
1826
+ }
1827
+ if (obj instanceof Uint8Array) {
1828
+ const numIdx = this.toInt(idx);
1829
+ return obj[numIdx];
1830
+ }
1831
+ throw new ParseError("Index access requires an array");
1832
+ }
1833
+ /**
1834
+ * Evaluate method call (object.method()).
1835
+ * @private
1836
+ */
1837
+ evaluateMethodCall(object, method, _args, context) {
1838
+ const obj = this.evaluate(object, context);
1839
+ if (method === "length" || method === "size") {
1840
+ if (Array.isArray(obj)) return obj.length;
1841
+ if (obj instanceof Uint8Array) return obj.length;
1842
+ if (typeof obj === "string") return obj.length;
1843
+ throw new ParseError(`Object does not have a ${method} property`);
1844
+ }
1845
+ if (method === "to_i") {
1846
+ return this.toInt(obj);
1847
+ }
1848
+ if (method === "to_s") {
1849
+ return String(obj);
1850
+ }
1851
+ throw new ParseError(`Unknown method: ${method}`);
1852
+ }
1853
+ /**
1854
+ * Evaluate enum access (EnumName::value).
1855
+ * @private
1856
+ */
1857
+ evaluateEnumAccess(enumName, valueName, context) {
1858
+ const value = context.getEnumValue(enumName, valueName);
1859
+ if (value === void 0) {
1860
+ throw new ParseError(`Enum value "${enumName}::${valueName}" not found`);
1861
+ }
1862
+ return value;
1863
+ }
1864
+ /**
1865
+ * Helper: Add two values (handles strings and numbers).
1866
+ * @private
1867
+ */
1868
+ add(left, right) {
1869
+ if (typeof left === "string" || typeof right === "string") {
1870
+ return String(left) + String(right);
1871
+ }
1872
+ return this.toNumber(left) + this.toNumber(right);
1873
+ }
1874
+ /**
1875
+ * Helper: Modulo operation (Kaitai-style, not remainder).
1876
+ * @private
1877
+ */
1878
+ modulo(a, b) {
1879
+ const result = a % b;
1880
+ return result < 0 ? result + b : result;
1881
+ }
1882
+ /**
1883
+ * Helper: Compare two values.
1884
+ * @private
1885
+ */
1886
+ compare(left, right) {
1887
+ if (typeof left === "string" && typeof right === "string") {
1888
+ return left < right ? -1 : left > right ? 1 : 0;
1889
+ }
1890
+ const leftNum = this.toNumber(left);
1891
+ const rightNum = this.toNumber(right);
1892
+ return leftNum < rightNum ? -1 : leftNum > rightNum ? 1 : 0;
1893
+ }
1894
+ /**
1895
+ * Helper: Check equality.
1896
+ * @private
1897
+ */
1898
+ equals(left, right) {
1899
+ if (typeof left === "bigint" || typeof right === "bigint") {
1900
+ return BigInt(left) === BigInt(right);
1901
+ }
1902
+ return left === right;
1903
+ }
1904
+ /**
1905
+ * Helper: Convert to number.
1906
+ * @private
1907
+ */
1908
+ toNumber(value) {
1909
+ if (typeof value === "number") return value;
1910
+ if (typeof value === "bigint") return Number(value);
1911
+ if (typeof value === "boolean") return value ? 1 : 0;
1912
+ if (typeof value === "string") return parseFloat(value);
1913
+ throw new ParseError(`Cannot convert ${typeof value} to number`);
1914
+ }
1915
+ /**
1916
+ * Helper: Convert to integer.
1917
+ * @private
1918
+ */
1919
+ toInt(value) {
1920
+ return Math.floor(this.toNumber(value));
1921
+ }
1922
+ /**
1923
+ * Helper: Convert to boolean.
1924
+ * @private
1925
+ */
1926
+ toBoolean(value) {
1927
+ if (typeof value === "boolean") return value;
1928
+ if (typeof value === "number") return value !== 0;
1929
+ if (typeof value === "bigint") return value !== 0n;
1930
+ if (typeof value === "string") return value.length > 0;
1931
+ if (value === null || value === void 0) return false;
1932
+ return true;
1933
+ }
1934
+ };
1935
+
1936
+ // src/expression/index.ts
1937
+ function evaluateExpression(expression, context) {
1938
+ const lexer = new Lexer(expression);
1939
+ const tokens = lexer.tokenize();
1940
+ const parser = new ExpressionParser(tokens);
1941
+ const ast = parser.parse();
1942
+ const evaluator = new Evaluator();
1943
+ return evaluator.evaluate(ast, context);
1944
+ }
1945
+
1005
1946
  // src/interpreter/TypeInterpreter.ts
1006
1947
  var TypeInterpreter = class _TypeInterpreter {
1007
1948
  /**
@@ -1025,12 +1966,21 @@ var TypeInterpreter = class _TypeInterpreter {
1025
1966
  *
1026
1967
  * @param stream - Binary stream to parse
1027
1968
  * @param parent - Parent object (for nested types)
1969
+ * @param typeArgs - Arguments for parametric types
1028
1970
  * @returns Parsed object
1029
1971
  */
1030
- parse(stream, parent) {
1972
+ parse(stream, parent, typeArgs) {
1031
1973
  const result = {};
1032
- const context = new Context(stream, result, parent);
1974
+ const context = new Context(stream, result, parent, this.schema.enums);
1033
1975
  context.current = result;
1976
+ if (typeArgs && this.schema.params) {
1977
+ for (let i = 0; i < this.schema.params.length && i < typeArgs.length; i++) {
1978
+ const param = this.schema.params[i];
1979
+ const argValue = typeArgs[i];
1980
+ const evaluatedArg = typeof argValue === "string" ? this.evaluateValue(argValue, context) : argValue;
1981
+ context.set(param.id, evaluatedArg);
1982
+ }
1983
+ }
1034
1984
  if (this.schema.seq) {
1035
1985
  for (const attr of this.schema.seq) {
1036
1986
  const value = this.parseAttribute(attr, context);
@@ -1039,8 +1989,83 @@ var TypeInterpreter = class _TypeInterpreter {
1039
1989
  }
1040
1990
  }
1041
1991
  }
1992
+ if (this.schema.instances) {
1993
+ this.setupInstances(result, stream, context);
1994
+ }
1042
1995
  return result;
1043
1996
  }
1997
+ /**
1998
+ * Set up lazy-evaluated instance getters.
1999
+ * Instances are computed on first access and cached.
2000
+ *
2001
+ * @param result - Result object to add getters to
2002
+ * @param stream - Stream for parsing
2003
+ * @param context - Execution context
2004
+ * @private
2005
+ */
2006
+ setupInstances(result, stream, context) {
2007
+ if (!this.schema.instances) return;
2008
+ for (const [name, instance] of Object.entries(this.schema.instances)) {
2009
+ let cached = void 0;
2010
+ let evaluated = false;
2011
+ Object.defineProperty(result, name, {
2012
+ get: () => {
2013
+ if (!evaluated) {
2014
+ cached = this.parseInstance(
2015
+ instance,
2016
+ stream,
2017
+ context
2018
+ );
2019
+ evaluated = true;
2020
+ }
2021
+ return cached;
2022
+ },
2023
+ enumerable: true,
2024
+ configurable: true
2025
+ });
2026
+ }
2027
+ }
2028
+ /**
2029
+ * Parse an instance (lazy-evaluated field).
2030
+ *
2031
+ * @param instance - Instance specification
2032
+ * @param stream - Stream to read from
2033
+ * @param context - Execution context
2034
+ * @returns Parsed or calculated value
2035
+ * @private
2036
+ */
2037
+ parseInstance(instance, stream, context) {
2038
+ if ("value" in instance) {
2039
+ return this.evaluateValue(
2040
+ instance.value,
2041
+ context
2042
+ );
2043
+ }
2044
+ const savedPos = stream.pos;
2045
+ try {
2046
+ if (instance.pos !== void 0) {
2047
+ const pos = this.evaluateValue(
2048
+ instance.pos,
2049
+ context
2050
+ );
2051
+ if (typeof pos === "number") {
2052
+ stream.seek(pos);
2053
+ } else if (typeof pos === "bigint") {
2054
+ stream.seek(Number(pos));
2055
+ } else {
2056
+ throw new ParseError(
2057
+ `pos must evaluate to a number, got ${typeof pos}`
2058
+ );
2059
+ }
2060
+ }
2061
+ const value = this.parseAttribute(instance, context);
2062
+ return value;
2063
+ } finally {
2064
+ if (instance.pos !== void 0) {
2065
+ stream.seek(savedPos);
2066
+ }
2067
+ }
2068
+ }
1044
2069
  /**
1045
2070
  * Parse a single attribute according to its specification.
1046
2071
  *
@@ -1052,11 +2077,20 @@ var TypeInterpreter = class _TypeInterpreter {
1052
2077
  parseAttribute(attr, context) {
1053
2078
  const stream = context.io;
1054
2079
  if (attr.if) {
1055
- throw new NotImplementedError("Conditional parsing (if)");
2080
+ const condition = this.evaluateValue(attr.if, context);
2081
+ if (!condition) {
2082
+ return void 0;
2083
+ }
1056
2084
  }
1057
2085
  if (attr.pos !== void 0) {
1058
- const pos = typeof attr.pos === "number" ? attr.pos : 0;
1059
- stream.seek(pos);
2086
+ const pos = this.evaluateValue(attr.pos, context);
2087
+ if (typeof pos === "number") {
2088
+ stream.seek(pos);
2089
+ } else if (typeof pos === "bigint") {
2090
+ stream.seek(Number(pos));
2091
+ } else {
2092
+ throw new ParseError(`pos must evaluate to a number, got ${typeof pos}`);
2093
+ }
1060
2094
  }
1061
2095
  if (attr.io) {
1062
2096
  throw new NotImplementedError("Custom I/O streams");
@@ -1067,7 +2101,8 @@ var TypeInterpreter = class _TypeInterpreter {
1067
2101
  if (attr.contents) {
1068
2102
  return this.parseContents(attr, context);
1069
2103
  }
1070
- return this.parseValue(attr, context);
2104
+ const value = this.parseValue(attr, context);
2105
+ return value;
1071
2106
  }
1072
2107
  /**
1073
2108
  * Parse a repeated attribute.
@@ -1078,14 +2113,22 @@ var TypeInterpreter = class _TypeInterpreter {
1078
2113
  * @private
1079
2114
  */
1080
2115
  parseRepeated(attr, context) {
1081
- const result = [];
1082
2116
  const stream = context.io;
2117
+ const result = [];
1083
2118
  switch (attr.repeat) {
1084
2119
  case "expr": {
1085
- const count = typeof attr["repeat-expr"] === "number" ? attr["repeat-expr"] : 0;
2120
+ const countValue = this.evaluateValue(attr["repeat-expr"], context);
2121
+ const count = typeof countValue === "number" ? countValue : typeof countValue === "bigint" ? Number(countValue) : 0;
2122
+ if (count < 0) {
2123
+ throw new ParseError(`repeat-expr must be non-negative, got ${count}`);
2124
+ }
1086
2125
  for (let i = 0; i < count; i++) {
1087
2126
  context.set("_index", i);
1088
- result.push(this.parseValue(attr, context));
2127
+ const value = this.parseAttribute(
2128
+ { ...attr, repeat: void 0, "repeat-expr": void 0 },
2129
+ context
2130
+ );
2131
+ result.push(value);
1089
2132
  }
1090
2133
  break;
1091
2134
  }
@@ -1100,7 +2143,25 @@ var TypeInterpreter = class _TypeInterpreter {
1100
2143
  if (!attr["repeat-until"]) {
1101
2144
  throw new ParseError("repeat-until expression is required");
1102
2145
  }
1103
- throw new NotImplementedError("repeat-until");
2146
+ let index = 0;
2147
+ while (true) {
2148
+ context.set("_index", index);
2149
+ const value = this.parseAttribute(
2150
+ { ...attr, repeat: void 0, "repeat-until": void 0 },
2151
+ context
2152
+ );
2153
+ result.push(value);
2154
+ context.set("_", value);
2155
+ const condition = this.evaluateValue(attr["repeat-until"], context);
2156
+ if (condition) {
2157
+ break;
2158
+ }
2159
+ if (stream.isEof()) {
2160
+ break;
2161
+ }
2162
+ index++;
2163
+ }
2164
+ break;
1104
2165
  }
1105
2166
  default:
1106
2167
  throw new ParseError(`Unknown repeat type: ${attr.repeat}`);
@@ -1153,17 +2214,34 @@ var TypeInterpreter = class _TypeInterpreter {
1153
2214
  const stream = context.io;
1154
2215
  const type = attr.type;
1155
2216
  if (attr.size !== void 0) {
1156
- const size = typeof attr.size === "number" ? attr.size : 0;
2217
+ const sizeValue = this.evaluateValue(attr.size, context);
2218
+ const size = typeof sizeValue === "number" ? sizeValue : typeof sizeValue === "bigint" ? Number(sizeValue) : 0;
2219
+ if (size < 0) {
2220
+ throw new ParseError(`size must be non-negative, got ${size}`);
2221
+ }
1157
2222
  if (type === "str" || !type) {
1158
2223
  const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
2224
+ let data;
1159
2225
  if (type === "str") {
1160
- return stream.readStr(size, encoding);
2226
+ data = stream.readBytes(size);
2227
+ if (attr.process) {
2228
+ data = this.applyProcessing(data, attr.process);
2229
+ }
2230
+ return new TextDecoder(encoding).decode(data);
1161
2231
  } else {
1162
- return stream.readBytes(size);
2232
+ data = stream.readBytes(size);
2233
+ if (attr.process) {
2234
+ data = this.applyProcessing(data, attr.process);
2235
+ }
2236
+ return data;
1163
2237
  }
1164
2238
  } else {
1165
- const substream = stream.substream(size);
1166
- return this.parseType(type, substream, context);
2239
+ let data = stream.readBytes(size);
2240
+ if (attr.process) {
2241
+ data = this.applyProcessing(data, attr.process);
2242
+ }
2243
+ const substream = new KaitaiStream(data);
2244
+ return this.parseType(type, substream, context, attr["type-args"]);
1167
2245
  }
1168
2246
  }
1169
2247
  if (attr["size-eos"]) {
@@ -1178,7 +2256,7 @@ var TypeInterpreter = class _TypeInterpreter {
1178
2256
  if (!type) {
1179
2257
  throw new ParseError("Attribute must have either type, size, or contents");
1180
2258
  }
1181
- return this.parseType(type, stream, context);
2259
+ return this.parseType(type, stream, context, attr["type-args"]);
1182
2260
  }
1183
2261
  /**
1184
2262
  * Parse a value of a specific type.
@@ -1186,12 +2264,17 @@ var TypeInterpreter = class _TypeInterpreter {
1186
2264
  * @param type - Type name or switch specification
1187
2265
  * @param stream - Stream to read from
1188
2266
  * @param context - Execution context
2267
+ * @param typeArgs - Arguments for parametric types
1189
2268
  * @returns Parsed value
1190
2269
  * @private
1191
2270
  */
1192
- parseType(type, stream, context) {
2271
+ parseType(type, stream, context, typeArgs) {
1193
2272
  if (typeof type === "object") {
1194
- throw new NotImplementedError("Switch types");
2273
+ return this.parseSwitchType(
2274
+ type,
2275
+ stream,
2276
+ context
2277
+ );
1195
2278
  }
1196
2279
  if (isBuiltinType(type)) {
1197
2280
  return this.parseBuiltinType(type, stream, context);
@@ -1199,11 +2282,49 @@ var TypeInterpreter = class _TypeInterpreter {
1199
2282
  if (this.schema.types && type in this.schema.types) {
1200
2283
  const typeSchema = this.schema.types[type];
1201
2284
  const meta = this.schema.meta || this.parentMeta;
2285
+ if (this.schema.enums && !typeSchema.enums) {
2286
+ typeSchema.enums = this.schema.enums;
2287
+ }
2288
+ if (this.schema.types && !typeSchema.types) {
2289
+ typeSchema.types = this.schema.types;
2290
+ }
1202
2291
  const interpreter = new _TypeInterpreter(typeSchema, meta);
1203
- return interpreter.parse(stream, context.current);
2292
+ return interpreter.parse(stream, context.current, typeArgs);
1204
2293
  }
1205
2294
  throw new ParseError(`Unknown type: ${type}`);
1206
2295
  }
2296
+ /**
2297
+ * Parse a switch type (type selection based on expression).
2298
+ *
2299
+ * @param switchType - Switch type specification
2300
+ * @param stream - Stream to read from
2301
+ * @param context - Execution context
2302
+ * @returns Parsed value
2303
+ * @private
2304
+ */
2305
+ parseSwitchType(switchType, stream, context) {
2306
+ const switchOn = switchType["switch-on"];
2307
+ const cases = switchType["cases"];
2308
+ const defaultType = switchType["default"];
2309
+ if (!switchOn || typeof switchOn !== "string") {
2310
+ throw new ParseError("switch-on expression is required for switch types");
2311
+ }
2312
+ if (!cases) {
2313
+ throw new ParseError("cases are required for switch types");
2314
+ }
2315
+ const switchValue = this.evaluateValue(switchOn, context);
2316
+ const switchKey = String(switchValue);
2317
+ let selectedType = cases[switchKey];
2318
+ if (selectedType === void 0 && defaultType) {
2319
+ selectedType = defaultType;
2320
+ }
2321
+ if (selectedType === void 0) {
2322
+ throw new ParseError(
2323
+ `No matching case for switch value "${switchKey}" and no default type specified`
2324
+ );
2325
+ }
2326
+ return this.parseType(selectedType, stream, context);
2327
+ }
1207
2328
  /**
1208
2329
  * Parse a built-in type.
1209
2330
  *
@@ -1280,6 +2401,50 @@ var TypeInterpreter = class _TypeInterpreter {
1280
2401
  throw new ParseError(`Unknown float type: ${type}`);
1281
2402
  }
1282
2403
  }
2404
+ /**
2405
+ * Apply processing transformation to data.
2406
+ * Supports basic transformations like zlib decompression.
2407
+ *
2408
+ * @param data - Data to process
2409
+ * @param process - Processing specification
2410
+ * @returns Processed data
2411
+ * @private
2412
+ */
2413
+ applyProcessing(data, process) {
2414
+ const processType = typeof process === "string" ? process : process.algorithm;
2415
+ if (processType) {
2416
+ throw new NotImplementedError(
2417
+ `Processing type "${processType}" is not yet implemented. Supported in future versions with zlib, encryption, etc.`
2418
+ );
2419
+ }
2420
+ return data;
2421
+ }
2422
+ /**
2423
+ * Evaluate a value that can be an expression or literal.
2424
+ *
2425
+ * @param value - Value to evaluate (expression string, number, or boolean)
2426
+ * @param context - Execution context
2427
+ * @returns Evaluated result
2428
+ * @private
2429
+ */
2430
+ evaluateValue(value, context) {
2431
+ if (value === void 0) {
2432
+ return void 0;
2433
+ }
2434
+ if (typeof value === "number" || typeof value === "boolean") {
2435
+ return value;
2436
+ }
2437
+ if (typeof value === "string") {
2438
+ try {
2439
+ return evaluateExpression(value, context);
2440
+ } catch (error) {
2441
+ throw new ParseError(
2442
+ `Failed to evaluate expression "${value}": ${error instanceof Error ? error.message : String(error)}`
2443
+ );
2444
+ }
2445
+ }
2446
+ return value;
2447
+ }
1283
2448
  };
1284
2449
 
1285
2450
  // src/index.ts
@@ -1359,6 +2524,42 @@ function parse(ksyYaml, buffer, options = {}) {
1359
2524
  * @author Fabiano Pinto
1360
2525
  * @license MIT
1361
2526
  */
2527
+ /**
2528
+ * @fileoverview Token types for Kaitai Struct expression language
2529
+ * @module expression/Token
2530
+ * @author Fabiano Pinto
2531
+ * @license MIT
2532
+ */
2533
+ /**
2534
+ * @fileoverview Lexer for Kaitai Struct expression language
2535
+ * @module expression/Lexer
2536
+ * @author Fabiano Pinto
2537
+ * @license MIT
2538
+ */
2539
+ /**
2540
+ * @fileoverview Abstract Syntax Tree nodes for expression language
2541
+ * @module expression/AST
2542
+ * @author Fabiano Pinto
2543
+ * @license MIT
2544
+ */
2545
+ /**
2546
+ * @fileoverview Parser for Kaitai Struct expression language
2547
+ * @module expression/Parser
2548
+ * @author Fabiano Pinto
2549
+ * @license MIT
2550
+ */
2551
+ /**
2552
+ * @fileoverview Evaluator for Kaitai Struct expression AST
2553
+ * @module expression/Evaluator
2554
+ * @author Fabiano Pinto
2555
+ * @license MIT
2556
+ */
2557
+ /**
2558
+ * @fileoverview Expression evaluation module
2559
+ * @module expression
2560
+ * @author Fabiano Pinto
2561
+ * @license MIT
2562
+ */
1362
2563
  /**
1363
2564
  * @fileoverview Type interpreter for executing Kaitai Struct schemas
1364
2565
  * @module interpreter/TypeInterpreter