Skip to content

Commit 82acf8d

Browse files
committed
Merge #93 inheritance for stateful lexers
Merge branch 'include'
2 parents 8c3e622 + 88cbef4 commit 82acf8d

File tree

1 file changed

+61
-5
lines changed

1 file changed

+61
-5
lines changed

moo.js

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@
6060
for (var i = 0; i < keys.length; i++) {
6161
var key = keys[i]
6262
var thing = object[key]
63-
var rules = Array.isArray(thing) ? thing : [thing]
63+
var rules = [].concat(thing)
64+
if (key === 'include') {
65+
for (var j = 0; j < rules.length; j++) {
66+
result.push({include: rules[j]})
67+
}
68+
continue
69+
}
6470
var match = []
6571
rules.forEach(function(rule) {
6672
if (isObject(rule)) {
@@ -80,6 +86,13 @@
8086
var result = []
8187
for (var i = 0; i < array.length; i++) {
8288
var obj = array[i]
89+
if (obj.include) {
90+
var include = [].concat(obj.include)
91+
for (var j = 0; j < include.length; j++) {
92+
result.push({include: include[j]})
93+
}
94+
continue
95+
}
8396
if (!obj.name) {
8497
throw new Error('Rule has no name: ' + JSON.stringify(obj))
8598
}
@@ -92,6 +105,9 @@
92105
if (!isObject(obj)) {
93106
obj = { match: obj }
94107
}
108+
if (obj.include) {
109+
throw new Error('Matching rules cannot also include states')
110+
}
95111

96112
// nb. error and fallback imply lineBreaks
97113
var options = {
@@ -127,10 +143,12 @@
127143
return options
128144
}
129145

146+
function toRules(spec) {
147+
return Array.isArray(spec) ? arrayToRules(spec) : objectToRules(spec)
148+
}
149+
130150
var defaultErrorRule = ruleOptions('error', {lineBreaks: true, shouldThrow: true})
131151
function compileRules(rules, hasStates) {
132-
rules = Array.isArray(rules) ? arrayToRules(rules) : objectToRules(rules)
133-
134152
var errorRule = null
135153
var fast = Object.create(null)
136154
var fastAllowed = true
@@ -139,6 +157,11 @@
139157
for (var i = 0; i < rules.length; i++) {
140158
var options = rules[i]
141159

160+
if (options.include) {
161+
// all valid inclusions are removed by states() preprocessor
162+
throw new Error('Inheritance is not allowed in stateless lexers')
163+
}
164+
142165
if (options.error || options.fallback) {
143166
// errorRule can only be set once
144167
if (errorRule) {
@@ -214,7 +237,7 @@
214237
}
215238

216239
function compile(rules) {
217-
var result = compileRules(rules)
240+
var result = compileRules(toRules(rules))
218241
return new Lexer({start: result}, 'start')
219242
}
220243

@@ -228,13 +251,46 @@
228251
}
229252
}
230253
function compileStates(states, start) {
254+
var all = states.$all ? toRules(states.$all) : []
255+
delete states.$all
256+
231257
var keys = Object.getOwnPropertyNames(states)
232258
if (!start) start = keys[0]
233259

260+
var ruleMap = Object.create(null)
261+
for (var i = 0; i < keys.length; i++) {
262+
var key = keys[i]
263+
ruleMap[key] = toRules(states[key]).concat(all)
264+
}
265+
for (var i = 0; i < keys.length; i++) {
266+
var key = keys[i]
267+
var rules = ruleMap[key]
268+
var included = Object.create(null)
269+
for (var j = 0; j < rules.length; j++) {
270+
var rule = rules[j]
271+
if (!rule.include) continue
272+
var splice = [j, 1]
273+
if (rule.include !== key && !included[rule.include]) {
274+
included[rule.include] = true
275+
var newRules = ruleMap[rule.include]
276+
if (!newRules) {
277+
throw new Error("Cannot include nonexistent state '" + rule.include + "' (in state '" + key + "')")
278+
}
279+
for (var k = 0; k < newRules.length; k++) {
280+
var newRule = newRules[k]
281+
if (rules.indexOf(newRule) !== -1) continue
282+
splice.push(newRule)
283+
}
284+
}
285+
rules.splice.apply(rules, splice)
286+
j--
287+
}
288+
}
289+
234290
var map = Object.create(null)
235291
for (var i = 0; i < keys.length; i++) {
236292
var key = keys[i]
237-
map[key] = compileRules(states[key], true)
293+
map[key] = compileRules(ruleMap[key], true)
238294
}
239295

240296
for (var i = 0; i < keys.length; i++) {

0 commit comments

Comments
 (0)