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
```