Skip to content

Commit e093f8c

Browse files
bgotinklarsgw
authored andcommitted
perf(parser): remove backtracking
1 parent 7495071 commit e093f8c

File tree

2 files changed

+87
-54
lines changed

2 files changed

+87
-54
lines changed

src/parser/base.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,13 @@ class BaseParser extends EmbeddedActionsParser {
7979
})
8080

8181
/**
82-
* Consume a value
83-
* @method #value
82+
* Consume a non-string value
83+
* @method #nonStringValue
8484
* @memberof module:kdljs.parser.base.BaseParser
8585
* @return {module:kdljs~Value}
8686
*/
87-
this.RULE('value', () => {
87+
this.RULE('nonStringValue', () => {
8888
return this.OR([
89-
{ ALT: () => this.SUBRULE(this.string) },
9089
{ ALT: () => this.CONSUME(Tokens.Boolean).image === '#true' },
9190
{
9291
ALT: () => {
@@ -117,6 +116,19 @@ class BaseParser extends EmbeddedActionsParser {
117116
])
118117
})
119118

119+
/**
120+
* Consume a value
121+
* @method #value
122+
* @memberof module:kdljs.parser.base.BaseParser
123+
* @return {module:kdljs~Value}
124+
*/
125+
this.RULE('value', () => {
126+
return this.OR([
127+
{ ALT: () => this.SUBRULE(this.string) },
128+
{ ALT: () => this.SUBRULE(this.nonStringValue) }
129+
])
130+
})
131+
120132
/**
121133
* Consume a normal string
122134
* @method #string
@@ -376,12 +388,15 @@ class BaseParser extends EmbeddedActionsParser {
376388
* Consume node space
377389
* @method #nodeSpace
378390
* @memberof module:kdljs.parser.kdl.BaseParser
391+
* @returns {boolean}
379392
*/
380393
this.RULE('nodeSpace', () => {
381394
this.AT_LEAST_ONE(() => this.OR([
382395
{ ALT: () => this.SUBRULE(this.whiteSpace) },
383396
{ ALT: () => this.SUBRULE(this.lineContinuation) }
384397
]))
398+
399+
return true
385400
})
386401

387402
/**

src/parser/kdl.js

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -143,26 +143,24 @@ class KdlParser extends BaseParser {
143143
let entriesEnded = false
144144
let childrenEnded = false
145145

146+
let hasSpace = this.OPTION2(() => this.SUBRULE1(this.nodeSpace))
147+
146148
this.MANY({
147-
GATE: () => !nodeEndTokens.has(this.LA(1).tokenType),
149+
GATE: () => hasSpace && !nodeEndTokens.has(this.LA(1).tokenType),
148150
DEF: () => {
149-
this.SUBRULE1(this.nodeSpace)
150-
151151
this.OR([
152152
{
153-
GATE: () => !entriesEnded && this.BACKTRACK(this.property).call(this),
153+
GATE: () => !entriesEnded,
154154
ALT: () => {
155-
const parts = this.SUBRULE(this.property)
156-
node.properties[parts[0]] = parts[1]
157-
node.tags.properties[parts[0]] = parts[2]
158-
}
159-
},
160-
{
161-
GATE: () => !entriesEnded && this.BACKTRACK(this.argument).call(this),
162-
ALT: () => {
163-
const parts = this.SUBRULE(this.argument)
164-
node.values.push(parts[0])
165-
node.tags.values.push(parts[1])
155+
const parts = this.SUBRULE(this.propertyOrArgument)
156+
if (parts[0] != null) {
157+
node.properties[parts[0]] = parts[1]
158+
node.tags.properties[parts[0]] = parts[2]
159+
} else {
160+
node.values.push(parts[1])
161+
node.tags.values.push(parts[2])
162+
}
163+
hasSpace = parts[3]
166164
}
167165
},
168166
{
@@ -171,33 +169,30 @@ class KdlParser extends BaseParser {
171169
node.children = this.SUBRULE(this.nodeChildren)
172170
entriesEnded = true
173171
childrenEnded = true
172+
hasSpace = this.OPTION3(() => this.SUBRULE2(this.nodeSpace))
174173
}
175174
},
176175
{
177176
ALT: () => {
178177
this.CONSUME(Tokens.BlockComment)
179-
this.OPTION2(() => this.SUBRULE(this.lineSpace))
178+
this.OPTION4(() => this.SUBRULE(this.lineSpace))
180179
this.OR1([
181180
{
182-
GATE: () => !entriesEnded && this.BACKTRACK(this.property).call(this),
183-
ALT: () => this.SUBRULE1(this.property)
184-
},
185-
{
186-
GATE: () => !entriesEnded && this.BACKTRACK(this.argument).call(this),
187-
ALT: () => this.SUBRULE1(this.argument)
181+
GATE: () => !entriesEnded,
182+
ALT: () => {
183+
const parts = this.SUBRULE1(this.propertyOrArgument)
184+
hasSpace = parts[3]
185+
}
188186
},
189187
{
190188
ALT: () => {
191189
this.SUBRULE1(this.nodeChildren)
192190
entriesEnded = true
191+
hasSpace = this.OPTION5(() => this.SUBRULE3(this.nodeSpace))
193192
}
194193
}
195194
])
196195
}
197-
},
198-
{
199-
GATE: () => nodeEndTokens.has(this.LA(1).tokenType),
200-
ALT: () => {}
201196
}
202197
])
203198
}
@@ -211,34 +206,57 @@ class KdlParser extends BaseParser {
211206
})
212207

213208
/**
214-
* Consume a property
215-
* @method #property
209+
* Consume a property or an argument
210+
* @method #propertyOrArgument
216211
* @memberof module:kdljs.parser.kdl.KdlParser
217212
* @return {Array<module:kdljs~Value>} key-value-type tuple
218213
*/
219-
this.RULE('property', () => {
220-
const key = this.SUBRULE(this.string)
221-
this.OPTION(() => this.SUBRULE(this.nodeSpace))
222-
this.CONSUME(Tokens.Equals)
223-
this.OPTION1(() => this.SUBRULE1(this.nodeSpace))
224-
const parts = this.SUBRULE(this.argument)
225-
return [key, parts[0], parts[1]]
226-
})
214+
this.RULE('propertyOrArgument', () => {
215+
return this.OR([
216+
{
217+
ALT: () => {
218+
const tag = this.SUBRULE(this.tag)
219+
this.OPTION(() => this.SUBRULE(this.nodeSpace))
220+
const value = this.SUBRULE(this.value)
221+
const hasSpaceAfter = this.OPTION1(() => this.SUBRULE1(this.nodeSpace))
222+
return [undefined, value, tag, hasSpaceAfter]
223+
}
224+
},
225+
{
226+
ALT: () => {
227+
const value = this.SUBRULE(this.nonStringValue)
228+
const hasSpaceAfter = this.OPTION2(() => this.SUBRULE2(this.nodeSpace))
229+
return [undefined, value, undefined, hasSpaceAfter]
230+
}
231+
},
232+
{
233+
ALT: () => {
234+
let name
235+
let tag
227236

228-
/**
229-
* Consume an argument
230-
* @method #argument
231-
* @memberof module:kdljs.parser.kdl.KdlParser
232-
* @return {Array<module:kdljs~Value>} value-type tuple
233-
*/
234-
this.RULE('argument', () => {
235-
const tag = this.OPTION(() => {
236-
const tag = this.SUBRULE(this.tag)
237-
this.OPTION1(() => this.SUBRULE(this.nodeSpace))
238-
return tag
239-
})
240-
const value = this.SUBRULE(this.value)
241-
return [value, tag]
237+
let value = this.SUBRULE(this.string)
238+
let hasSpaceAfter = this.OPTION3(() => this.SUBRULE3(this.nodeSpace))
239+
240+
this.OPTION4(() => {
241+
this.CONSUME(Tokens.Equals)
242+
this.OPTION5(() => this.SUBRULE4(this.nodeSpace))
243+
244+
name = value
245+
246+
tag = this.OPTION6(() => {
247+
const tag = this.SUBRULE1(this.tag)
248+
this.OPTION7(() => this.SUBRULE5(this.nodeSpace))
249+
return tag
250+
})
251+
252+
value = this.SUBRULE1(this.value)
253+
hasSpaceAfter = this.OPTION8(() => this.SUBRULE6(this.nodeSpace))
254+
})
255+
256+
return [name, value, tag, hasSpaceAfter]
257+
}
258+
}
259+
])
242260
})
243261

244262
/**

0 commit comments

Comments
 (0)