or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

binary-parsing.mdcombinators.mdcore-parsers.mdindex.mdlanguage-creation.mdstring-parsers.mdtransformation.md

transformation.mddocs/

0

# Parser Transformation

1

2

Instance methods for transforming and chaining parsers. These methods enable building complex parsing pipelines by combining and transforming simpler parsers.

3

4

## Capabilities

5

6

### Result Transformation

7

8

Methods that transform the result of a successful parse.

9

10

```javascript { .api }

11

/**

12

* Transform parser result using a function

13

* @param {Function} fn - Function to transform the result

14

* @returns {Parser} Parser with transformed result

15

*/

16

parser.map(fn);

17

18

/**

19

* Replace parser result with a constant value

20

* @param {any} value - Value to use as result

21

* @returns {Parser} Parser that returns the constant value

22

*/

23

parser.result(value);

24

25

/**

26

* Transform input before parsing (contravariant map)

27

* @param {Function} fn - Function to transform input

28

* @returns {Parser} Parser that operates on transformed input

29

*/

30

parser.contramap(fn);

31

32

/**

33

* Transform both input and output

34

* @param {Function} f - Function to transform input

35

* @param {Function} g - Function to transform output

36

* @returns {Parser} Parser with both transformations

37

*/

38

parser.promap(f, g);

39

```

40

41

**Usage Examples:**

42

43

```javascript

44

// Basic transformation

45

const number = Parsimmon.digits.map(Number);

46

number.parse("42"); // { status: true, value: 42 }

47

48

// Transform to constant

49

const trueParser = Parsimmon.string("yes").result(true);

50

trueParser.parse("yes"); // { status: true, value: true }

51

52

// Transform input

53

const caseInsensitive = Parsimmon.string("hello")

54

.contramap(input => input.toLowerCase());

55

caseInsensitive.parse("HELLO"); // { status: true, value: "hello" }

56

57

// Transform both input and output

58

const upperDigits = Parsimmon.digits

59

.promap(

60

input => input.toLowerCase(), // normalize input

61

result => result.toUpperCase() // transform output

62

);

63

64

// Complex transformations

65

const coordinate = Parsimmon.seqMap(

66

Parsimmon.digits.map(Number),

67

Parsimmon.string(","),

68

Parsimmon.digits.map(Number),

69

(x, _, y) => ({ x, y, distance: Math.sqrt(x*x + y*y) })

70

);

71

```

72

73

### String Manipulation

74

75

Methods for working with string results.

76

77

```javascript { .api }

78

/**

79

* Concatenate array result to single string

80

* @returns {Parser} Parser that returns joined string

81

*/

82

parser.tie();

83

84

/**

85

* Concatenate array result with separator

86

* @param {string} separator - String to join array elements

87

* @returns {Parser} Parser that returns joined string

88

*/

89

parser.tieWith(separator);

90

```

91

92

**Usage Examples:**

93

94

```javascript

95

// Join characters

96

const letters = Parsimmon.letter.many().tie();

97

letters.parse("hello"); // { status: true, value: "hello" }

98

99

// Join with separator

100

const words = Parsimmon.letters.sepBy(Parsimmon.whitespace).tieWith(" ");

101

words.parse("hello world"); // { status: true, value: "hello world" }

102

103

// Parse hex bytes

104

const hexPair = Parsimmon.regexp(/[0-9a-fA-F]/).times(2).tie();

105

const hexString = hexPair.sepBy(Parsimmon.string(" ")).tieWith("");

106

hexString.parse("A1 B2 C3"); // { status: true, value: "A1B2C3" }

107

```

108

109

### Parser Chaining

110

111

Methods that chain parsers together in sequence or conditionally.

112

113

```javascript { .api }

114

/**

115

* Monadic bind - chain dependent parsers

116

* @param {Function} fn - Function that returns next parser based on result

117

* @returns {Parser} Parser with conditional chaining

118

*/

119

parser.chain(fn);

120

121

/**

122

* Parse this parser then another, return second result

123

* @param {Parser} next - Parser to run after this one

124

* @returns {Parser} Parser that returns result of next

125

*/

126

parser.then(next);

127

128

/**

129

* Parse this parser then another, return first result

130

* @param {Parser} next - Parser to run after this one

131

* @returns {Parser} Parser that returns result of this

132

*/

133

parser.skip(next);

134

```

135

136

**Usage Examples:**

137

138

```javascript

139

// Conditional parsing with chain

140

const numberParser = Parsimmon.digits.chain(function(digits) {

141

const num = Number(digits);

142

if (num > 100) {

143

return Parsimmon.fail("number too large");

144

}

145

return Parsimmon.succeed(num);

146

});

147

148

// Dynamic parsing based on first result

149

const taggedValue = Parsimmon.letters.chain(function(tag) {

150

if (tag === "num") {

151

return Parsimmon.string(":").then(Parsimmon.digits.map(Number));

152

} else if (tag === "str") {

153

return Parsimmon.string(":").then(Parsimmon.regexp(/[^,]*/));

154

} else {

155

return Parsimmon.fail("unknown tag: " + tag);

156

}

157

});

158

159

// Sequence with then/skip

160

const assignment = Parsimmon.letters

161

.skip(Parsimmon.string("=").trim(Parsimmon.optWhitespace))

162

.then(Parsimmon.digits.map(Number));

163

164

assignment.parse("x = 42"); // { status: true, value: 42 }

165

166

// Parse between delimiters

167

const quoted = Parsimmon.string('"')

168

.then(Parsimmon.regexp(/[^"]*/))

169

.skip(Parsimmon.string('"'));

170

```

171

172

### Parser Combination

173

174

Methods that combine this parser with alternatives or conditions.

175

176

```javascript { .api }

177

/**

178

* Try alternative parser if this one fails

179

* @param {Parser} alternative - Parser to try if this fails

180

* @returns {Parser} Parser that tries alternative on failure

181

*/

182

parser.or(alternative);

183

184

/**

185

* Provide fallback value if parser fails

186

* @param {any} value - Value to return on failure

187

* @returns {Parser} Parser with fallback value

188

*/

189

parser.fallback(value);

190

191

/**

192

* Assert condition on result, fail with message if false

193

* @param {Function} condition - Predicate function for result

194

* @param {string} message - Error message if condition fails

195

* @returns {Parser} Parser with assertion

196

*/

197

parser.assert(condition, message);

198

```

199

200

**Usage Examples:**

201

202

```javascript

203

// Try alternatives

204

const booleanValue = Parsimmon.string("true")

205

.result(true)

206

.or(Parsimmon.string("false").result(false));

207

208

// Provide defaults

209

const optionalName = Parsimmon.string("name:")

210

.then(Parsimmon.letters)

211

.fallback("anonymous");

212

213

// Validate results

214

const positiveNumber = Parsimmon.digits

215

.map(Number)

216

.assert(n => n > 0, "positive number required");

217

218

// Complex validation

219

const email = Parsimmon.regexp(/[^@]+@[^@]+\.[^@]+/)

220

.assert(s => s.includes("."), "email must contain domain")

221

.assert(s => s.length < 100, "email too long");

222

```

223

224

### Repetition Methods

225

226

Methods that repeat a parser multiple times.

227

228

```javascript { .api }

229

/**

230

* Repeat parser zero or more times

231

* @returns {Parser} Parser that returns array of results

232

*/

233

parser.many();

234

235

/**

236

* Repeat parser exactly n times, or between min and max times

237

* @param {number} min - Minimum repetitions (or exact if max not given)

238

* @param {number} [max] - Maximum repetitions

239

* @returns {Parser} Parser that returns array of results

240

*/

241

parser.times(min, max);

242

243

/**

244

* Repeat parser at most n times

245

* @param {number} n - Maximum repetitions

246

* @returns {Parser} Parser that returns array of results

247

*/

248

parser.atMost(n);

249

250

/**

251

* Repeat parser at least n times

252

* @param {number} n - Minimum repetitions

253

* @returns {Parser} Parser that returns array of results

254

*/

255

parser.atLeast(n);

256

```

257

258

**Usage Examples:**

259

260

```javascript

261

// Parse multiple items

262

const numbers = Parsimmon.digits.map(Number).many();

263

numbers.parse("123456"); // { status: true, value: [1,2,3,4,5,6] }

264

265

// Exact repetition

266

const hexByte = Parsimmon.regexp(/[0-9a-fA-F]/).times(2).tie();

267

hexByte.parse("a1"); // { status: true, value: "a1" }

268

269

// Range repetition

270

const identifier = Parsimmon.regexp(/[a-zA-Z_]/)

271

.then(Parsimmon.regexp(/[a-zA-Z0-9_]/).times(0, 63))

272

.map(([first, rest]) => first + rest.join(""));

273

274

// At least/at most

275

const someDigits = Parsimmon.digit.atLeast(1).tie();

276

const fewDigits = Parsimmon.digit.atMost(3).tie();

277

278

// Parse comma-separated with repetition

279

const csvRow = Parsimmon.regexp(/[^,\n]*/)

280

.sepBy(Parsimmon.string(","))

281

.skip(Parsimmon.newline.atMost(1));

282

```

283

284

### Separated Repetition

285

286

Instance methods for parsing lists with separators.

287

288

```javascript { .api }

289

/**

290

* Parse zero or more of this parser separated by separator

291

* @param {Parser} separator - Parser for separator

292

* @returns {Parser} Parser that returns array of results

293

*/

294

parser.sepBy(separator);

295

296

/**

297

* Parse one or more of this parser separated by separator

298

* @param {Parser} separator - Parser for separator

299

* @returns {Parser} Parser that returns array of results

300

*/

301

parser.sepBy1(separator);

302

```

303

304

**Usage Examples:**

305

306

```javascript

307

// Parse word lists

308

const wordList = Parsimmon.letters.sepBy(Parsimmon.string(","));

309

wordList.parse("apple,banana,cherry"); // { status: true, value: ["apple","banana","cherry"] }

310

311

// Parse with required elements

312

const nonEmptyList = Parsimmon.digits.map(Number).sepBy1(Parsimmon.string("|"));

313

nonEmptyList.parse("1|2|3"); // { status: true, value: [1,2,3] }

314

nonEmptyList.parse(""); // { status: false, ... }

315

316

// Parse with complex separators

317

const parameter = Parsimmon.letters;

318

const paramList = parameter.sepBy(

319

Parsimmon.string(",").trim(Parsimmon.optWhitespace)

320

);

321

```

322

323

### String Manipulation

324

325

Methods for working with array results as strings.

326

327

```javascript { .api }

328

/**

329

* Join array of strings with separator

330

* @param {string} separator - String to join with

331

* @returns {Parser} Parser that returns joined string

332

*/

333

parser.tieWith(separator);

334

335

/**

336

* Join array of strings with no separator

337

* @returns {Parser} Parser that returns concatenated string

338

*/

339

parser.tie();

340

```

341

342

**Usage Examples:**

343

344

```javascript

345

// Collect characters into string

346

const word = Parsimmon.letter.many().tie();

347

word.parse("hello"); // { status: true, value: "hello" }

348

349

// Join with separator

350

const spacedWord = Parsimmon.letter.many().tieWith(" ");

351

spacedWord.parse("hello"); // { status: true, value: "h e l l o" }

352

353

// Parse dotted identifiers

354

const dottedId = Parsimmon.letters.sepBy1(Parsimmon.string(".")).tieWith(".");

355

dottedId.parse("foo.bar.baz"); // { status: true, value: "foo.bar.baz" }

356

```

357

358

### Position and Context

359

360

Methods for working with parsing position and context.

361

362

```javascript { .api }

363

/**

364

* Mark result with start and end positions

365

* @returns {Parser} Parser that returns {start, value, end}

366

*/

367

parser.mark();

368

369

/**

370

* Create AST node with name and position

371

* @param {string} name - Node name

372

* @returns {Parser} Parser that returns {name, value, start, end}

373

*/

374

parser.node(name);

375

376

/**

377

* Apply wrapper function to this parser

378

* @param {Function} wrapper - Function that takes and returns a parser

379

* @returns {Parser} Result of wrapper function

380

*/

381

parser.thru(wrapper);

382

```

383

384

**Usage Examples:**

385

386

```javascript

387

// Track positions

388

const markedNumber = Parsimmon.digits.map(Number).mark();

389

markedNumber.parse("123");

390

// { status: true, value: { start: {offset:0, line:1, col:1}, value: 123, end: {offset:3, line:1, col:4} } }

391

392

// Create AST nodes

393

const numberNode = Parsimmon.digits.map(Number).node("Number");

394

numberNode.parse("42");

395

// { status: true, value: { name: "Number", value: 42, start: {...}, end: {...} } }

396

397

// Apply transformations

398

const trimmed = Parsimmon.string("hello").thru(p =>

399

Parsimmon.optWhitespace.then(p).skip(Parsimmon.optWhitespace)

400

);

401

402

// Reusable wrapper

403

const token = (parser) => parser.trim(Parsimmon.optWhitespace);

404

const numberToken = Parsimmon.digits.map(Number).thru(token);

405

```

406

407

### Lookahead and Validation

408

409

Methods for conditional parsing and validation.

410

411

```javascript { .api }

412

/**

413

* Ensure parser is followed by another parser

414

* @param {Parser|string|RegExp} x - Parser, string, or regex that should follow

415

* @returns {Parser} Parser that checks lookahead

416

*/

417

parser.lookahead(x);

418

419

/**

420

* Ensure parser is not followed by another parser

421

* @param {Parser} x - Parser that should not follow

422

* @returns {Parser} Parser that checks negative lookahead

423

*/

424

parser.notFollowedBy(x);

425

426

/**

427

* Wrap parser between left and right parsers

428

* @param {Parser} left - Parser for left delimiter

429

* @param {Parser} right - Parser for right delimiter

430

* @returns {Parser} Parser that returns middle value

431

*/

432

parser.wrap(left, right);

433

434

/**

435

* Trim parser with whitespace (or specified parser)

436

* @param {Parser} [parser] - Parser to use for trimming (default: optWhitespace)

437

* @returns {Parser} Parser with trimming

438

*/

439

parser.trim(parser);

440

441

/**

442

* Provide custom error description

443

* @param {string|string[]} description - Error description

444

* @returns {Parser} Parser with custom error messages

445

*/

446

parser.desc(description);

447

```

448

449

**Usage Examples:**

450

451

```javascript

452

// Lookahead validation

453

const keyword = Parsimmon.string("if")

454

.notFollowedBy(Parsimmon.regexp(/[a-zA-Z0-9_]/));

455

456

keyword.parse("if"); // Success

457

keyword.parse("ifdef"); // Fails

458

459

// Wrap between delimiters

460

const parenthesized = Parsimmon.digits.wrap(

461

Parsimmon.string("("),

462

Parsimmon.string(")")

463

);

464

parenthesized.parse("(123)"); // { status: true, value: "123" }

465

466

// Trim whitespace

467

const trimmedNumber = Parsimmon.digits.trim(Parsimmon.optWhitespace);

468

trimmedNumber.parse(" 42 "); // { status: true, value: "42" }

469

470

// Custom error messages

471

const email = Parsimmon.regexp(/[^@]+@[^@]+/)

472

.desc("valid email address");

473

474

email.parse("invalid"); // Error mentions "valid email address"

475

```