@futpib/parser 1.0.7 → 1.0.8

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.
@@ -0,0 +1,3 @@
1
+ import * as fc from 'fast-check';
2
+ import { type BashCommandList } from './bash.js';
3
+ export declare const arbitraryBashCommandList: fc.Arbitrary<BashCommandList>;
@@ -0,0 +1,142 @@
1
+ import * as fc from 'fast-check';
2
+ const arbitraryBashIdentifier = fc.stringMatching(/^[a-zA-Z_][a-zA-Z0-9_]*$/);
3
+ // Safe unquoted literal: no shell special chars, no leading {/} or #, no = (would be parsed as assignment)
4
+ const arbitraryBashWordPartLiteral = fc.record({
5
+ type: fc.constant('literal'),
6
+ value: fc.stringMatching(/^[a-zA-Z0-9][a-zA-Z0-9._@%,:^~-]*$/),
7
+ });
8
+ // Single-quoted: no single quotes, no newlines inside (keep simple)
9
+ const arbitraryBashWordPartSingleQuoted = fc.record({
10
+ type: fc.constant('singleQuoted'),
11
+ value: fc.stringMatching(/^[^'\n]*$/),
12
+ });
13
+ const arbitraryBashWordPartVariable = fc.record({
14
+ type: fc.constant('variable'),
15
+ name: arbitraryBashIdentifier,
16
+ });
17
+ // variableBraced without operator/operand (always include the optional keys so deepEqual matches parser output)
18
+ const arbitraryBashWordPartVariableBraced = fc.record({
19
+ type: fc.constant('variableBraced'),
20
+ name: arbitraryBashIdentifier,
21
+ operator: fc.constant(undefined),
22
+ operand: fc.constant(undefined),
23
+ });
24
+ const arbitraryBashWordPartArithmeticExpansion = fc.record({
25
+ type: fc.constant('arithmeticExpansion'),
26
+ expression: fc.stringMatching(/^[0-9+\- ]*$/),
27
+ });
28
+ const recursiveArbitraries = fc.letrec(tie => {
29
+ const arbitraryCommandList = tie('commandList');
30
+ // Double-quoted literal: no shell-special chars inside double quotes
31
+ const arbitraryDoubleQuotedLiteral = fc.record({
32
+ type: fc.constant('literal'),
33
+ value: fc.stringMatching(/^[^"\\$`\n]+$/),
34
+ });
35
+ const arbitraryBashWordPartDoubleQuoted = fc.record({
36
+ type: fc.constant('doubleQuoted'),
37
+ parts: fc.array(fc.oneof({ weight: 3, arbitrary: arbitraryDoubleQuotedLiteral }, { weight: 1, arbitrary: arbitraryBashWordPartVariable }, { weight: 1, arbitrary: arbitraryBashWordPartVariableBraced }), { minLength: 1, maxLength: 3 }),
38
+ }).filter(dq => dq.parts.every((part, i) => {
39
+ const next = dq.parts[i + 1];
40
+ // Prevent adjacent literal parts (they merge when re-parsed)
41
+ if (part.type === 'literal' && next !== undefined && next.type === 'literal') {
42
+ return false;
43
+ }
44
+ // Prevent $var followed by literal starting with ident char (would be mis-parsed as one variable)
45
+ if (part.type === 'variable' && next !== undefined && next.type === 'literal') {
46
+ return next.value.length === 0 || !isIdentChar(next.value[0]);
47
+ }
48
+ return true;
49
+ }));
50
+ const arbitraryBashWordPartCommandSubstitution = fc.record({
51
+ type: fc.constant('commandSubstitution'),
52
+ command: arbitraryCommandList,
53
+ });
54
+ const arbitraryBashWordPart = fc.oneof({ weight: 4, arbitrary: arbitraryBashWordPartLiteral }, { weight: 2, arbitrary: arbitraryBashWordPartSingleQuoted }, { weight: 2, arbitrary: arbitraryBashWordPartDoubleQuoted }, { weight: 2, arbitrary: arbitraryBashWordPartVariable }, { weight: 1, arbitrary: arbitraryBashWordPartVariableBraced }, { weight: 1, arbitrary: arbitraryBashWordPartArithmeticExpansion }, { weight: 1, arbitrary: arbitraryBashWordPartCommandSubstitution });
55
+ function isIdentChar(ch) {
56
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch === '_';
57
+ }
58
+ const arbitraryWord = fc.record({
59
+ parts: fc.array(arbitraryBashWordPart, { minLength: 1, maxLength: 2 }),
60
+ }).filter(word => word.parts.every((part, i) => {
61
+ const next = word.parts[i + 1];
62
+ // Prevent adjacent literal parts (they merge when re-parsed)
63
+ if (part.type === 'literal' && next !== undefined && next.type === 'literal') {
64
+ return false;
65
+ }
66
+ // Prevent $var followed by literal starting with ident char (would be mis-parsed as one variable)
67
+ if (part.type === 'variable' && next !== undefined && next.type === 'literal') {
68
+ return next.value.length === 0 || !isIdentChar(next.value[0]);
69
+ }
70
+ return true;
71
+ }));
72
+ // Always include value key (even if undefined) to match createObjectParser behavior
73
+ const arbitraryBashAssignment = fc.record({
74
+ name: arbitraryBashIdentifier,
75
+ value: fc.option(arbitraryWord, { nil: undefined }),
76
+ });
77
+ // Always include fd key (even if undefined) to match createObjectParser behavior
78
+ const arbitraryBashRedirect = fc.record({
79
+ fd: fc.constant(undefined),
80
+ operator: fc.oneof(fc.constant('>'), fc.constant('>>'), fc.constant('<')),
81
+ target: arbitraryWord,
82
+ });
83
+ const arbitraryBashSimpleCommandWithName = fc.record({
84
+ type: fc.constant('simple'),
85
+ name: arbitraryWord,
86
+ args: fc.array(arbitraryWord, { maxLength: 2 }),
87
+ redirects: fc.array(arbitraryBashRedirect, { maxLength: 1 }),
88
+ assignments: fc.array(arbitraryBashAssignment, { maxLength: 1 }),
89
+ });
90
+ // Commands with no name: only assignments and/or redirects (no args)
91
+ const arbitraryBashSimpleCommandNoName = fc.record({
92
+ type: fc.constant('simple'),
93
+ name: fc.constant(undefined),
94
+ args: fc.constant([]),
95
+ redirects: fc.array(arbitraryBashRedirect, { maxLength: 1 }),
96
+ assignments: fc.array(arbitraryBashAssignment, { minLength: 1, maxLength: 2 }),
97
+ });
98
+ const arbitraryBashSimpleCommand = fc.oneof({ weight: 4, arbitrary: arbitraryBashSimpleCommandWithName }, { weight: 1, arbitrary: arbitraryBashSimpleCommandNoName });
99
+ const arbitraryBashSubshell = fc.record({
100
+ type: fc.constant('subshell'),
101
+ body: arbitraryCommandList,
102
+ });
103
+ // Brace group bodies need trailing ';' on last entry (required by "{ cmd; }" syntax)
104
+ const arbitraryBraceGroupBody = arbitraryCommandList.map(list => {
105
+ const entries = list.entries.map((entry, i) => {
106
+ if (i === list.entries.length - 1 && entry.separator === undefined) {
107
+ return { pipeline: entry.pipeline, separator: ';' };
108
+ }
109
+ return entry;
110
+ });
111
+ return { ...list, entries };
112
+ });
113
+ const arbitraryBashBraceGroup = fc.record({
114
+ type: fc.constant('braceGroup'),
115
+ body: arbitraryBraceGroupBody,
116
+ });
117
+ const arbitraryBashCommandUnit = fc.oneof({ weight: 5, arbitrary: arbitraryBashSimpleCommand }, { weight: 1, arbitrary: arbitraryBashSubshell }, { weight: 1, arbitrary: arbitraryBashBraceGroup });
118
+ const arbitraryBashPipeline = fc.record({
119
+ type: fc.constant('pipeline'),
120
+ negated: fc.boolean(),
121
+ commands: fc.array(arbitraryBashCommandUnit, { minLength: 1, maxLength: 2 }),
122
+ });
123
+ const commandListArbitrary = fc.record({
124
+ type: fc.constant('list'),
125
+ entries: fc.array(fc.record({
126
+ pipeline: arbitraryBashPipeline,
127
+ separator: fc.option(fc.oneof(fc.constant('&&'), fc.constant('||'), fc.constant(';')), { nil: undefined }),
128
+ }), { minLength: 1, maxLength: 2 }),
129
+ }).map(list => {
130
+ const entries = list.entries.map((entry, i) => {
131
+ if (i < list.entries.length - 1 && entry.separator === undefined) {
132
+ return { pipeline: entry.pipeline, separator: ';' };
133
+ }
134
+ return entry;
135
+ });
136
+ return { ...list, entries };
137
+ });
138
+ return {
139
+ commandList: commandListArbitrary,
140
+ };
141
+ });
142
+ export const arbitraryBashCommandList = recursiveArbitraries.commandList;
@@ -164,7 +164,7 @@ const arbitraryFunctionBodyBlockStatement = fc.record({
164
164
  const arbitraryArrowFunctionExpression = fc.oneof(fc.record({
165
165
  type: fc.constant('ArrowFunctionExpression'),
166
166
  id: fc.constant(null),
167
- params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
167
+ params: fc.uniqueArray(arbitraryIdentifier, { minLength: 0, maxLength: 3, selector: (id) => id.name }),
168
168
  body: arbitraryFunctionBodyBlockStatement,
169
169
  expression: fc.constant(false),
170
170
  generator: fc.constant(false),
@@ -172,7 +172,7 @@ const arbitraryArrowFunctionExpression = fc.oneof(fc.record({
172
172
  }), fc.record({
173
173
  type: fc.constant('ArrowFunctionExpression'),
174
174
  id: fc.constant(null),
175
- params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
175
+ params: fc.uniqueArray(arbitraryIdentifier, { minLength: 0, maxLength: 3, selector: (id) => id.name }),
176
176
  body: arbitraryLeafExpression,
177
177
  expression: fc.constant(true),
178
178
  generator: fc.constant(false),
@@ -181,7 +181,7 @@ const arbitraryArrowFunctionExpression = fc.oneof(fc.record({
181
181
  const arbitraryFunctionExpression = fc.record({
182
182
  type: fc.constant('FunctionExpression'),
183
183
  id: fc.constant(null),
184
- params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
184
+ params: fc.uniqueArray(arbitraryIdentifier, { minLength: 0, maxLength: 3, selector: (id) => id.name }),
185
185
  body: arbitraryFunctionBodyBlockStatement,
186
186
  expression: fc.constant(false),
187
187
  generator: fc.constant(false),
@@ -232,7 +232,7 @@ const arbitraryTryStatement = fc.oneof(fc.record({
232
232
  const arbitraryFunctionDeclaration = fc.record({
233
233
  type: fc.constant('FunctionDeclaration'),
234
234
  id: arbitraryIdentifier,
235
- params: fc.array(arbitraryIdentifier, { minLength: 0, maxLength: 3 }),
235
+ params: fc.uniqueArray(arbitraryIdentifier, { minLength: 0, maxLength: 3, selector: (id) => id.name }),
236
236
  body: arbitraryFunctionBodyBlockStatement,
237
237
  expression: fc.constant(false),
238
238
  generator: fc.constant(false),
@@ -2,4 +2,4 @@ import { type ZipEntry } from './zip.js';
2
2
  export declare const arbitraryZipStream: import("fast-check").Arbitrary<readonly [{
3
3
  comment: string;
4
4
  entries: ZipEntry[];
5
- }, import("stream/web").ReadableStream<Uint8Array<ArrayBufferLike>>]>;
5
+ }, import("node:stream/web").ReadableStream<Uint8Array<ArrayBufferLike>>]>;
@@ -0,0 +1,3 @@
1
+ import { type Unparser } from './unparser.js';
2
+ import { type BashCommand } from './bash.js';
3
+ export declare const bashScriptUnparser: Unparser<BashCommand, string>;
@@ -0,0 +1,157 @@
1
+ function isIdentChar(ch) {
2
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch === '_';
3
+ }
4
+ function nextPartStartsWithIdentChar(parts, index) {
5
+ const next = parts[index + 1];
6
+ if (next === undefined) {
7
+ return false;
8
+ }
9
+ if (next.type === 'literal') {
10
+ return next.value.length > 0 && isIdentChar(next.value[0]);
11
+ }
12
+ return false;
13
+ }
14
+ function unparseWord(word) {
15
+ return word.parts.map((part, i) => unparseWordPartInContext(part, word.parts, i)).join('');
16
+ }
17
+ function unparseWordPartInContext(part, parts, index) {
18
+ return unparseWordPart(part);
19
+ }
20
+ function unparseWordPart(part) {
21
+ switch (part.type) {
22
+ case 'literal':
23
+ return escapeLiteral(part.value);
24
+ case 'singleQuoted':
25
+ return "'" + part.value + "'";
26
+ case 'doubleQuoted':
27
+ return '"' + part.parts.map(p => unparseDoubleQuotedPart(p)).join('') + '"';
28
+ case 'variable':
29
+ return '$' + part.name;
30
+ case 'variableBraced': {
31
+ let result = '${' + part.name;
32
+ if (part.operator !== undefined) {
33
+ result += part.operator;
34
+ if (part.operand !== undefined) {
35
+ result += unparseWord(part.operand);
36
+ }
37
+ }
38
+ result += '}';
39
+ return result;
40
+ }
41
+ case 'commandSubstitution':
42
+ return '$( ' + unparseCommand(part.command) + ' )';
43
+ case 'backtickSubstitution':
44
+ return '`' + unparseCommand(part.command) + '`';
45
+ case 'arithmeticExpansion':
46
+ return '$((' + part.expression + '))';
47
+ case 'processSubstitution':
48
+ return part.direction + '(' + unparseCommand(part.command) + ')';
49
+ }
50
+ }
51
+ function unparseDoubleQuotedPart(part) {
52
+ switch (part.type) {
53
+ case 'literal': {
54
+ let result = '';
55
+ for (const ch of part.value) {
56
+ if (ch === '\\' || ch === '$' || ch === '`' || ch === '"') {
57
+ result += '\\' + ch;
58
+ }
59
+ else {
60
+ result += ch;
61
+ }
62
+ }
63
+ return result;
64
+ }
65
+ default:
66
+ return unparseWordPart(part);
67
+ }
68
+ }
69
+ function escapeLiteral(value) {
70
+ let result = '';
71
+ for (const ch of value) {
72
+ if (' \t\n|&;<>()$`"\' \\'.includes(ch) || ch === '{' || ch === '}' || ch === '#') {
73
+ result += '\\' + ch;
74
+ }
75
+ else {
76
+ result += ch;
77
+ }
78
+ }
79
+ return result;
80
+ }
81
+ function unparseRedirect(redirect) {
82
+ let result = '';
83
+ if (redirect.fd !== undefined) {
84
+ result += String(redirect.fd);
85
+ }
86
+ result += redirect.operator;
87
+ if ('type' in redirect.target && redirect.target.type === 'hereDoc') {
88
+ result += redirect.target.delimiter;
89
+ }
90
+ else {
91
+ result += unparseWord(redirect.target);
92
+ }
93
+ return result;
94
+ }
95
+ function unparseAssignment(assignment) {
96
+ let result = assignment.name + '=';
97
+ if (assignment.value !== undefined) {
98
+ result += unparseWord(assignment.value);
99
+ }
100
+ return result;
101
+ }
102
+ function unparseSimpleCommand(cmd) {
103
+ const parts = [];
104
+ for (const assignment of cmd.assignments) {
105
+ parts.push(unparseAssignment(assignment));
106
+ }
107
+ if (cmd.name !== undefined) {
108
+ parts.push(unparseWord(cmd.name));
109
+ }
110
+ for (const arg of cmd.args) {
111
+ parts.push(unparseWord(arg));
112
+ }
113
+ const wordParts = parts.join(' ');
114
+ const redirectParts = cmd.redirects.map(r => unparseRedirect(r)).join(' ');
115
+ if (redirectParts) {
116
+ return wordParts ? wordParts + ' ' + redirectParts : redirectParts;
117
+ }
118
+ return wordParts;
119
+ }
120
+ function unparseCommandUnit(unit) {
121
+ switch (unit.type) {
122
+ case 'simple':
123
+ return unparseSimpleCommand(unit);
124
+ case 'subshell':
125
+ return '(' + unparseCommand(unit.body) + ')';
126
+ case 'braceGroup':
127
+ return '{ ' + unparseCommand(unit.body) + ' }';
128
+ }
129
+ }
130
+ function unparsePipeline(pipeline) {
131
+ let result = '';
132
+ if (pipeline.negated) {
133
+ result += '! ';
134
+ }
135
+ result += pipeline.commands.map(cmd => unparseCommandUnit(cmd)).join(' | ');
136
+ return result;
137
+ }
138
+ function unparseCommand(command) {
139
+ return unparseCommandList(command);
140
+ }
141
+ function unparseCommandList(list) {
142
+ let result = '';
143
+ for (let i = 0; i < list.entries.length; i++) {
144
+ const entry = list.entries[i];
145
+ if (i > 0) {
146
+ result += ' ';
147
+ }
148
+ result += unparsePipeline(entry.pipeline);
149
+ if (entry.separator !== undefined) {
150
+ result += entry.separator;
151
+ }
152
+ }
153
+ return result;
154
+ }
155
+ export const bashScriptUnparser = async function* (command) {
156
+ yield unparseCommand(command);
157
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { testProp } from '@fast-check/ava';
2
+ import { arbitraryBashCommandList } from './arbitraryBash.js';
3
+ import { bashScriptUnparser } from './bashUnparser.js';
4
+ import { bashScriptParser } from './bashParser.js';
5
+ import { runParser } from './parser.js';
6
+ import { runUnparser } from './unparser.js';
7
+ import { stringParserInputCompanion } from './parserInputCompanion.js';
8
+ import { stringUnparserOutputCompanion } from './unparserOutputCompanion.js';
9
+ const seed = process.env.SEED ? Number(process.env.SEED) : undefined;
10
+ async function collectString(asyncIterable) {
11
+ let result = '';
12
+ for await (const chunk of asyncIterable) {
13
+ result += chunk;
14
+ }
15
+ return result;
16
+ }
17
+ testProp('bash roundtrip', [arbitraryBashCommandList], async (t, command) => {
18
+ const source = await collectString(runUnparser(bashScriptUnparser, command, stringUnparserOutputCompanion));
19
+ const reparsed = await runParser(bashScriptParser, source, stringParserInputCompanion);
20
+ t.deepEqual(reparsed, command);
21
+ }, {
22
+ verbose: true,
23
+ seed,
24
+ });
@@ -5,17 +5,17 @@ import { createTupleParser } from './tupleParser.js';
5
5
  import { createSkipParser } from './skipParser.js';
6
6
  import { createParserAccessorParser } from './parserAccessorParser.js';
7
7
  import { createTerminatedArrayParser } from './terminatedArrayParser.js';
8
- import { createElementParser } from './elementParser.js';
9
8
  import { createExactElementParser } from './exactElementParser.js';
10
9
  import { createUnionParser } from './unionParser.js';
11
10
  import { parserCreatorCompose } from './parserCreatorCompose.js';
11
+ import { createPredicateElementParser } from './predicateElementParser.js';
12
12
  const createFixedLengthBufferParser = (length) => promiseCompose(createFixedLengthSequenceParser(length), sequence => Buffer.from(sequence));
13
13
  const buffer1Parser = createFixedLengthBufferParser(1);
14
14
  const buffer4Parser = createFixedLengthBufferParser(4);
15
15
  const buffer8Parser = createFixedLengthBufferParser(8);
16
- const elementParser = createElementParser();
17
16
  const nullByteParser = createExactElementParser(0);
18
- const cstringParser = promiseCompose(createTerminatedArrayParser(parserCreatorCompose(() => elementParser, (byte) => async (parserContext) => parserContext.invariant(byte, 'Expected non-null byte'))(), nullByteParser), ([sequence]) => Buffer.from(sequence).toString('utf8'));
17
+ const nonNullByteParser = createPredicateElementParser((byte) => byte !== 0);
18
+ const cstringParser = promiseCompose(createTerminatedArrayParser(nonNullByteParser, nullByteParser), ([sequence]) => Buffer.from(sequence).toString('utf8'));
19
19
  const doubleParser = promiseCompose(buffer8Parser, buffer => buffer.readDoubleLE(0));
20
20
  setParserName(doubleParser, 'doubleParser');
21
21
  const int32Parser = promiseCompose(buffer4Parser, buffer => buffer.readInt32LE(0));
@@ -1,4 +1,3 @@
1
- import invariant from 'invariant';
2
1
  import { setParserName } from '../parser.js';
3
2
  import { promiseCompose } from '../promiseCompose.js';
4
3
  import { createSeparatedArrayParser } from '../separatedArrayParser.js';
@@ -6,36 +5,26 @@ import { createExactSequenceParser } from '../exactSequenceParser.js';
6
5
  import { createUnionParser } from '../unionParser.js';
7
6
  import { createTupleParser } from '../tupleParser.js';
8
7
  import { createArrayParser } from '../arrayParser.js';
9
- export const smaliSimpleNameParser = async (parserContext) => {
10
- const characters = [];
11
- while (true) {
12
- const character = await parserContext.peek(0);
13
- parserContext.invariant(character !== undefined, 'Unexpected end of input');
14
- invariant(character !== undefined, 'Unexpected end of input');
15
- if ((character >= 'a' && character <= 'z')
16
- || (character >= 'A' && character <= 'Z')
17
- || (character >= '0' && character <= '9')
18
- || (character === ' ')
19
- || (character === '$')
20
- || (character === '-')
21
- || (character === '_')
22
- || (character === '\u00A0')
23
- || (character >= '\u00A1' && character <= '\u1FFF')
24
- || (character >= '\u2000' && character <= '\u200A')
25
- || (character >= '\u2010' && character <= '\u2027')
26
- || (character === '\u202F')
27
- || (character >= '\u2030' && character <= '\uD7FF')
28
- || (character >= '\uE000' && character <= '\uFFEF')
29
- || (character >= '\uD800' && character <= '\uDBFF')) {
30
- parserContext.skip(1);
31
- characters.push(character);
32
- continue;
33
- }
34
- parserContext.invariant(characters.length > 0, 'Expected at least one character');
35
- break;
36
- }
37
- return characters.join('');
38
- };
8
+ import { createNonEmptyArrayParser } from '../nonEmptyArrayParser.js';
9
+ import { createPredicateElementParser } from '../predicateElementParser.js';
10
+ function isSmaliSimpleNameChar(character) {
11
+ return ((character >= 'a' && character <= 'z')
12
+ || (character >= 'A' && character <= 'Z')
13
+ || (character >= '0' && character <= '9')
14
+ || character === ' '
15
+ || character === '$'
16
+ || character === '-'
17
+ || character === '_'
18
+ || character === '\u00A0'
19
+ || (character >= '\u00A1' && character <= '\u1FFF')
20
+ || (character >= '\u2000' && character <= '\u200A')
21
+ || (character >= '\u2010' && character <= '\u2027')
22
+ || character === '\u202F'
23
+ || (character >= '\u2030' && character <= '\uD7FF')
24
+ || (character >= '\uE000' && character <= '\uFFEF')
25
+ || (character >= '\uD800' && character <= '\uDBFF'));
26
+ }
27
+ export const smaliSimpleNameParser = promiseCompose(createNonEmptyArrayParser(createPredicateElementParser(isSmaliSimpleNameChar)), characters => characters.join(''));
39
28
  setParserName(smaliSimpleNameParser, 'smaliSimpleNameParser');
40
29
  export const smaliMemberNameParser = createUnionParser([
41
30
  smaliSimpleNameParser,
@@ -12,6 +12,7 @@ import { createTupleParser } from './tupleParser.js';
12
12
  import { createParserAccessorParser } from './parserAccessorParser.js';
13
13
  import { createSkipToParser } from './skipToParser.js';
14
14
  import { createLookaheadParser } from './lookaheadParser.js';
15
+ import { createPredicateElementParser } from './predicateElementParser.js';
15
16
  import { getIsoTypedNumberArray, isoIndexIntoFieldIds, isoIndexIntoMethodIds, isoIndexIntoPrototypeIds, isoIndexIntoStringIds, isoIndexIntoTypeIds, isoOffsetFromEncodedCatchHandlerListToEncodedCatchHandler, isoOffsetToAnnotationItem, isoOffsetToAnnotationsDirectoryItem, isoOffsetToAnnotationSetItem, isoOffsetToAnnotationSetRefListItem, isoOffsetToClassDataItem, isoOffsetToCodeItem, isoOffsetToDebugInfoItem, isoOffsetToEncodedArrayItem, isoOffsetToStringDataItem, isoOffsetToTypeList, } from './dalvikExecutableParser/typedNumbers.js';
16
17
  import { sleb128NumberParser, uleb128NumberParser } from './leb128Parser.js';
17
18
  import { createDisjunctionParser } from './disjunctionParser.js';
@@ -354,11 +355,7 @@ const createSkipToThenClassDataItemsParser = (sizeOffset) => createSkipToThenIte
354
355
  parserName: 'skipToThenClassDataItemsParser',
355
356
  });
356
357
  const createByteWith5LeastSignificantBitsEqualParser = (leastSignificant5) => {
357
- const byteWith5LeastSignificantBitsEqualParser = async (parserContext) => {
358
- const byte = await parserContext.read(0);
359
- parserContext.invariant((byte & 0b0001_1111) === leastSignificant5, 'Expected byte with 5 least significant bits equal to %s, but got %s', leastSignificant5.toString(2).padStart(8, '0'), byte.toString(2).padStart(8, '0'));
360
- return byte;
361
- };
358
+ const byteWith5LeastSignificantBitsEqualParser = createPredicateElementParser((byte) => (byte & 0b0001_1111) === leastSignificant5);
362
359
  setParserName(byteWith5LeastSignificantBitsEqualParser, `createByteWith5LeastSignificantBitsEqualParser(${leastSignificant5.toString(2).padStart(5, '0')})`);
363
360
  return byteWith5LeastSignificantBitsEqualParser;
364
361
  };
@@ -1,6 +1,6 @@
1
1
  import { execa } from 'execa';
2
2
  export async function hasExecutable(executable) {
3
- const hasExecutable = execa(executable).catch(() => false).then(() => true);
3
+ const hasExecutable = await execa(executable).then(() => true).catch(() => false);
4
4
  if (!hasExecutable) {
5
5
  console.warn('Executable %o not found', executable);
6
6
  }
@@ -8,8 +8,7 @@ import { createDisjunctionParser } from './disjunctionParser.js';
8
8
  import { createTerminatedArrayParser } from './terminatedArrayParser.js';
9
9
  import { createArrayParser } from './arrayParser.js';
10
10
  import { createParserAccessorParser } from './parserAccessorParser.js';
11
- import { createElementParser } from './elementParser.js';
12
- import { parserCreatorCompose } from './parserCreatorCompose.js';
11
+ import { createPredicateElementParser } from './predicateElementParser.js';
13
12
  import { createSeparatedArrayParser } from './separatedArrayParser.js';
14
13
  import { createRegExpParser } from './regexpParser.js';
15
14
  const whitespaceParser = createArrayParser(createUnionParser([
@@ -41,13 +40,9 @@ const jsonStringEscapeSequenceParser = createUnionParser([
41
40
  jsonTabEscapeSequenceParser,
42
41
  jsonUnicodeEscapeSequenceParser,
43
42
  ]);
44
- const elementParser = createElementParser();
45
43
  const jsonStringCharacterParser = createDisjunctionParser([
46
44
  jsonStringEscapeSequenceParser,
47
- parserCreatorCompose(() => elementParser, character => async (parserContext) => {
48
- parserContext.invariant(character !== '"', 'Unexpected """');
49
- return character;
50
- })(),
45
+ createPredicateElementParser((character) => character !== '"'),
51
46
  ]);
52
47
  export const jsonStringParser = promiseCompose(createTupleParser([
53
48
  createExactSequenceParser('"'),
@@ -17,6 +17,14 @@ export type RepeatBounds = number | {
17
17
  min?: number;
18
18
  max: number;
19
19
  };
20
+ export declare enum AssertionSign {
21
+ POSITIVE = 0,
22
+ NEGATIVE = 1
23
+ }
24
+ export declare enum AssertionDir {
25
+ AHEAD = 0,
26
+ BEHIND = 1
27
+ }
20
28
  export type RegularExpression = {
21
29
  type: 'epsilon';
22
30
  } | {
@@ -48,10 +56,11 @@ export type RegularExpression = {
48
56
  inner: RegularExpression;
49
57
  name?: string;
50
58
  } | {
51
- type: 'lookahead';
52
- isPositive: boolean;
59
+ type: 'assertion';
60
+ direction: AssertionDir;
61
+ sign: AssertionSign;
53
62
  inner: RegularExpression;
54
- right: RegularExpression;
63
+ outer: RegularExpression;
55
64
  } | {
56
65
  type: 'start-anchor';
57
66
  left: RegularExpression;
@@ -1 +1,10 @@
1
- export {};
1
+ export var AssertionSign;
2
+ (function (AssertionSign) {
3
+ AssertionSign[AssertionSign["POSITIVE"] = 0] = "POSITIVE";
4
+ AssertionSign[AssertionSign["NEGATIVE"] = 1] = "NEGATIVE";
5
+ })(AssertionSign || (AssertionSign = {}));
6
+ export var AssertionDir;
7
+ (function (AssertionDir) {
8
+ AssertionDir[AssertionDir["AHEAD"] = 0] = "AHEAD";
9
+ AssertionDir[AssertionDir["BEHIND"] = 1] = "BEHIND";
10
+ })(AssertionDir || (AssertionDir = {}));