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

combinators.mddocs/

0

# Parser Combinators

1

2

Functions that combine multiple parsers into more complex parsing patterns. Combinators are the core building blocks for creating sophisticated parsers from simpler components.

3

4

## Capabilities

5

6

### Sequence Combinators

7

8

Combinators that parse multiple elements in sequence.

9

10

```javascript { .api }

11

/**

12

* Parses all given parsers in sequence, returns array of results

13

* @param {...Parser} parsers - Parsers to run in sequence

14

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

15

*/

16

Parsimmon.seq(p1, p2, ...pn);

17

18

/**

19

* Parses all parsers in sequence, applies mapper function to results

20

* @param {...Parser} parsers - Parsers to run in sequence

21

* @param {Function} mapper - Function applied to results array

22

* @returns {Parser} Parser that returns mapped result

23

*/

24

Parsimmon.seqMap(p1, p2, ...pn, mapper);

25

26

/**

27

* Parses parsers in sequence, returns object with named results

28

* @param {...(Parser|Array)} args - Parsers or [name, parser] pairs

29

* @returns {Parser} Parser that returns object with named properties

30

*/

31

Parsimmon.seqObj(...args);

32

```

33

34

**Usage Examples:**

35

36

```javascript

37

// Basic sequence - returns array

38

const pair = Parsimmon.seq(

39

Parsimmon.digits,

40

Parsimmon.string(","),

41

Parsimmon.digits

42

);

43

pair.parse("12,34"); // { status: true, value: ["12", ",", "34"] }

44

45

// Sequence with transformation

46

const coordinate = Parsimmon.seqMap(

47

Parsimmon.digits.map(Number),

48

Parsimmon.string(","),

49

Parsimmon.digits.map(Number),

50

(x, comma, y) => ({ x, y })

51

);

52

coordinate.parse("10,20"); // { status: true, value: { x: 10, y: 20 } }

53

54

// Named sequence - returns object

55

const point = Parsimmon.seqObj(

56

["x", Parsimmon.digits.map(Number)],

57

Parsimmon.string(","),

58

["y", Parsimmon.digits.map(Number)]

59

);

60

point.parse("15,25"); // { status: true, value: { x: 15, y: 25 } }

61

```

62

63

### Alternative Combinators

64

65

Combinators that try multiple parsing alternatives.

66

67

```javascript { .api }

68

/**

69

* Tries parsers in order, returns result of first success

70

* @param {...Parser} parsers - Parsers to try in order

71

* @returns {Parser} Parser that succeeds with first successful alternative

72

*/

73

Parsimmon.alt(p1, p2, ...pn);

74

```

75

76

**Usage Examples:**

77

78

```javascript

79

// Parse different number formats

80

const number = Parsimmon.alt(

81

Parsimmon.regexp(/0x[0-9a-fA-F]+/).map(s => parseInt(s, 16)), // hex

82

Parsimmon.regexp(/0b[01]+/).map(s => parseInt(s.slice(2), 2)), // binary

83

Parsimmon.regexp(/[0-9]+/).map(Number) // decimal

84

);

85

86

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

87

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

88

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

89

90

// Parse keywords or identifiers

91

const keywordOrId = Parsimmon.alt(

92

Parsimmon.string("if"),

93

Parsimmon.string("else"),

94

Parsimmon.string("while"),

95

Parsimmon.regexp(/[a-zA-Z][a-zA-Z0-9]*/)

96

);

97

```

98

99

### Separated Combinators

100

101

Combinators for parsing lists with separators.

102

103

```javascript { .api }

104

/**

105

* Parses zero or more content items separated by separator

106

* @param {Parser} content - Parser for list items

107

* @param {Parser} separator - Parser for separator between items

108

* @returns {Parser} Parser that returns array of content items

109

*/

110

Parsimmon.sepBy(content, separator);

111

112

/**

113

* Parses one or more content items separated by separator

114

* @param {Parser} content - Parser for list items

115

* @param {Parser} separator - Parser for separator between items

116

* @returns {Parser} Parser that returns array of content items

117

*/

118

Parsimmon.sepBy1(content, separator);

119

```

120

121

**Usage Examples:**

122

123

```javascript

124

// Parse comma-separated numbers

125

const numberList = Parsimmon.sepBy(

126

Parsimmon.digits.map(Number),

127

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

128

);

129

130

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

131

numberList.parse("42"); // { status: true, value: [42] }

132

numberList.parse(""); // { status: true, value: [] }

133

134

// Parse at least one item

135

const nonEmptyList = Parsimmon.sepBy1(

136

Parsimmon.letters,

137

Parsimmon.string("|")

138

);

139

140

nonEmptyList.parse("a|b|c"); // { status: true, value: ["a", "b", "c"] }

141

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

142

143

// Parse function arguments

144

const args = Parsimmon.string("(")

145

.then(Parsimmon.sepBy(

146

Parsimmon.regexp(/[^,)]+/).trim(Parsimmon.optWhitespace),

147

Parsimmon.string(",")

148

))

149

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

150

151

args.parse("(a, b, c)"); // { status: true, value: ["a", "b", "c"] }

152

```

153

154

### Lazy Evaluation

155

156

Combinators for handling recursive grammars and forward references.

157

158

```javascript { .api }

159

/**

160

* Creates a lazy parser for recursive grammars

161

* @param {Function} fn - Function that returns a parser

162

* @returns {Parser} Parser that evaluates lazily

163

*/

164

Parsimmon.lazy(fn);

165

166

/**

167

* Creates a lazy parser with description

168

* @param {string} description - Description for error messages

169

* @param {Function} fn - Function that returns a parser

170

* @returns {Parser} Parser that evaluates lazily

171

*/

172

Parsimmon.lazy(description, fn);

173

```

174

175

**Usage Examples:**

176

177

```javascript

178

// Recursive JSON-like structure

179

const value = Parsimmon.lazy(() => Parsimmon.alt(

180

Parsimmon.regexp(/"[^"]*"/).map(s => s.slice(1, -1)), // string

181

Parsimmon.digits.map(Number), // number

182

array,

183

object

184

));

185

186

const array = Parsimmon.string("[")

187

.then(Parsimmon.sepBy(value, Parsimmon.string(",").trim(Parsimmon.optWhitespace)))

188

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

189

190

const object = Parsimmon.string("{")

191

.then(Parsimmon.sepBy(

192

Parsimmon.seqMap(

193

Parsimmon.regexp(/"[^"]*"/).map(s => s.slice(1, -1)),

194

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

195

value,

196

(key, colon, val) => [key, val]

197

),

198

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

199

))

200

.skip(Parsimmon.string("}"))

201

.map(pairs => Object.fromEntries(pairs));

202

203

// Arithmetic expressions with precedence

204

const expr = Parsimmon.lazy("expression", () => addition);

205

206

const factor = Parsimmon.alt(

207

Parsimmon.digits.map(Number),

208

Parsimmon.string("(").then(expr).skip(Parsimmon.string(")"))

209

);

210

211

const term = Parsimmon.sepBy1(factor, Parsimmon.string("*"))

212

.map(factors => factors.reduce((a, b) => a * b));

213

214

const addition = Parsimmon.sepBy1(term, Parsimmon.string("+"))

215

.map(terms => terms.reduce((a, b) => a + b));

216

```

217

218

### Language Creation

219

220

Framework for creating complete parsing languages with interdependent rules.

221

222

```javascript { .api }

223

/**

224

* Creates a language object with interdependent parsers

225

* @param {Object} parsers - Object with parser-generating functions

226

* @returns {Object} Language object with parser properties

227

*/

228

Parsimmon.createLanguage(parsers);

229

```

230

231

**Usage Examples:**

232

233

```javascript

234

// Create a simple expression language

235

const MathLang = Parsimmon.createLanguage({

236

// Basic tokens

237

number: () => Parsimmon.regexp(/[0-9]+/).map(Number),

238

operator: () => Parsimmon.oneOf("+-*/"),

239

240

// Expressions using other rules

241

factor: (r) => Parsimmon.alt(

242

r.number,

243

Parsimmon.string("(").then(r.expr).skip(Parsimmon.string(")"))

244

),

245

246

term: (r) => Parsimmon.seqMap(

247

r.factor,

248

Parsimmon.seq(Parsimmon.oneOf("*/"), r.factor).many(),

249

(first, rest) => rest.reduce((acc, [op, val]) =>

250

op === "*" ? acc * val : acc / val, first)

251

),

252

253

expr: (r) => Parsimmon.seqMap(

254

r.term,

255

Parsimmon.seq(Parsimmon.oneOf("+-"), r.term).many(),

256

(first, rest) => rest.reduce((acc, [op, val]) =>

257

op === "+" ? acc + val : acc - val, first)

258

)

259

});

260

261

// Use the language

262

MathLang.expr.parse("2 + 3 * 4"); // { status: true, value: 14 }

263

264

// JSON parser using createLanguage

265

const JsonLang = Parsimmon.createLanguage({

266

value: (r) => Parsimmon.alt(

267

r.string, r.number, r.boolean, r.null, r.array, r.object

268

),

269

270

string: () => Parsimmon.regexp(/"((?:\\.|[^"\\])*)"/,1),

271

number: () => Parsimmon.regexp(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/).map(Number),

272

boolean: () => Parsimmon.alt(Parsimmon.string("true"), Parsimmon.string("false")).map(x => x === "true"),

273

null: () => Parsimmon.string("null").result(null),

274

275

array: (r) => Parsimmon.string("[")

276

.then(r.value.sepBy(Parsimmon.string(",").trim(Parsimmon.optWhitespace)))

277

.skip(Parsimmon.string("]")),

278

279

object: (r) => Parsimmon.string("{")

280

.then(Parsimmon.seqMap(

281

r.string,

282

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

283

r.value,

284

(key, _, value) => [key, value]

285

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

286

.skip(Parsimmon.string("}"))

287

.map(pairs => Object.fromEntries(pairs))

288

});

289

```