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

language-creation.mddocs/

0

# Language Creation

1

2

Framework for creating complete parsing languages with interdependent rules. This enables building complex parsers where rules can reference each other, including recursive and mutually recursive grammars.

3

4

## Capabilities

5

6

### Language Creation

7

8

Creates a language object with interdependent parsers that can reference each other by name.

9

10

```javascript { .api }

11

/**

12

* Creates a language object with interdependent parsers

13

* @param {Object} parsers - Object mapping names to parser functions

14

* @returns {Object} Language object with parser instances

15

*/

16

Parsimmon.createLanguage(parsers);

17

```

18

19

**Usage Examples:**

20

21

```javascript

22

// Simple arithmetic language

23

const Lang = Parsimmon.createLanguage({

24

Expr: function() {

25

return Parsimmon.alt(

26

this.AddExpr,

27

this.Number

28

);

29

},

30

31

AddExpr: function() {

32

return Parsimmon.seqMap(

33

this.Number,

34

Parsimmon.string('+').trim(Parsimmon.optWhitespace),

35

this.Expr,

36

(left, op, right) => ({ type: 'add', left, right })

37

);

38

},

39

40

Number: function() {

41

return Parsimmon.regexp(/[0-9]+/)

42

.map(Number)

43

.desc('number');

44

}

45

});

46

47

// Use the language

48

const result = Lang.Expr.parse("5 + 3 + 2");

49

// Returns: { type: 'add', left: 5, right: { type: 'add', left: 3, right: 2 } }

50

51

// More complex example with recursive structures

52

const JsonLang = Parsimmon.createLanguage({

53

value: function() {

54

return Parsimmon.alt(

55

this.string,

56

this.number,

57

this.object,

58

this.array,

59

this.bool,

60

this.null

61

);

62

},

63

64

object: function() {

65

return this.pair

66

.sepBy(this.comma)

67

.wrap(this.lbrace, this.rbrace)

68

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

69

},

70

71

array: function() {

72

return this.value

73

.sepBy(this.comma)

74

.wrap(this.lbracket, this.rbracket);

75

},

76

77

// ... other rules

78

});

79

```

80

81

### Lazy Parser Creation

82

83

Creates lazy parsers for recursive grammars where parsers need to reference themselves or other parsers that aren't defined yet.

84

85

```javascript { .api }

86

/**

87

* Creates a lazy parser for recursive grammars

88

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

89

* @returns {Parser} Lazy parser that evaluates when used

90

*/

91

Parsimmon.lazy(fn);

92

93

/**

94

* Creates a lazy parser with description for recursive grammars

95

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

96

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

97

* @returns {Parser} Lazy parser with description

98

*/

99

Parsimmon.lazy(description, fn);

100

```

101

102

**Usage Examples:**

103

104

```javascript

105

// Simple recursive parser

106

const parenExpr = Parsimmon.lazy(() => {

107

return Parsimmon.string('(')

108

.then(parenExpr.or(Parsimmon.regexp(/[^()]+/)))

109

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

110

});

111

112

// Lazy parser with description

113

const list = Parsimmon.lazy('list', () => {

114

return Parsimmon.string('[')

115

.then(

116

Parsimmon.alt(

117

list,

118

Parsimmon.regexp(/[^\[\]]+/)

119

)

120

)

121

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

122

});

123

124

// Mutual recursion example

125

let expr, term, factor;

126

127

expr = Parsimmon.lazy(() => {

128

return Parsimmon.alt(

129

Parsimmon.seqMap(

130

term,

131

Parsimmon.string('+'),

132

expr,

133

(l, op, r) => ({ type: 'add', left: l, right: r })

134

),

135

term

136

);

137

});

138

139

term = Parsimmon.lazy(() => {

140

return Parsimmon.alt(

141

Parsimmon.seqMap(

142

factor,

143

Parsimmon.string('*'),

144

term,

145

(l, op, r) => ({ type: 'mul', left: l, right: r })

146

),

147

factor

148

);

149

});

150

151

factor = Parsimmon.lazy(() => {

152

return Parsimmon.alt(

153

expr.wrap(Parsimmon.string('('), Parsimmon.string(')')),

154

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

155

);

156

});

157

```

158

159

## Best Practices

160

161

### Language Organization

162

163

When using `createLanguage`, organize your grammar rules logically:

164

165

- Start with the top-level rule (usually called `Expr`, `Program`, or similar)

166

- Define rules in order of precedence (higher precedence rules reference lower ones)

167

- Use clear, descriptive names for rules

168

- Add `.desc()` calls for better error messages

169

170

### Recursive Pattern Handling

171

172

For recursive structures:

173

174

- Use `lazy()` when a parser needs to reference itself before it's fully defined

175

- Use `createLanguage()` when you have multiple interdependent rules

176

- Always provide good descriptions for error reporting

177

- Be careful about left recursion (can cause infinite loops)

178

179

### Error Handling

180

181

Both `createLanguage` and `lazy` support proper error propagation:

182

183

```javascript

184

const Lang = Parsimmon.createLanguage({

185

expr: function() {

186

return this.number.desc('expected number');

187

},

188

189

number: function() {

190

return Parsimmon.regexp(/[0-9]+/)

191

.map(Number)

192

.desc('number');

193

}

194

});

195

196

// Provides clear error messages when parsing fails

197

```