@foxglove/omgidl-parser
Version:
Parse OMG IDL to flattened definitions for serialization
1,232 lines (1,112 loc) • 105 kB
JavaScript
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 694:
/***/ (function(module, exports) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function(root, factory) {
if (true) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) /* global define */
} else {}
}(this, function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty
var toString = Object.prototype.toString
var hasSticky = typeof new RegExp().sticky === 'boolean'
/***************************************************************************/
function isRegExp(o) { return o && toString.call(o) === '[object RegExp]' }
function isObject(o) { return o && typeof o === 'object' && !isRegExp(o) && !Array.isArray(o) }
function reEscape(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
}
function reGroups(s) {
var re = new RegExp('|' + s)
return re.exec('').length - 1
}
function reCapture(s) {
return '(' + s + ')'
}
function reUnion(regexps) {
if (!regexps.length) return '(?!)'
var source = regexps.map(function(s) {
return "(?:" + s + ")"
}).join('|')
return "(?:" + source + ")"
}
function regexpOrLiteral(obj) {
if (typeof obj === 'string') {
return '(?:' + reEscape(obj) + ')'
} else if (isRegExp(obj)) {
// TODO: consider /u support
if (obj.ignoreCase) throw new Error('RegExp /i flag not allowed')
if (obj.global) throw new Error('RegExp /g flag is implied')
if (obj.sticky) throw new Error('RegExp /y flag is implied')
if (obj.multiline) throw new Error('RegExp /m flag is implied')
return obj.source
} else {
throw new Error('Not a pattern: ' + obj)
}
}
function pad(s, length) {
if (s.length > length) {
return s
}
return Array(length - s.length + 1).join(" ") + s
}
function lastNLines(string, numLines) {
var position = string.length
var lineBreaks = 0;
while (true) {
var idx = string.lastIndexOf("\n", position - 1)
if (idx === -1) {
break;
} else {
lineBreaks++
}
position = idx
if (lineBreaks === numLines) {
break;
}
if (position === 0) {
break;
}
}
var startPosition =
lineBreaks < numLines ?
0 :
position + 1
return string.substring(startPosition).split("\n")
}
function objectToRules(object) {
var keys = Object.getOwnPropertyNames(object)
var result = []
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var thing = object[key]
var rules = [].concat(thing)
if (key === 'include') {
for (var j = 0; j < rules.length; j++) {
result.push({include: rules[j]})
}
continue
}
var match = []
rules.forEach(function(rule) {
if (isObject(rule)) {
if (match.length) result.push(ruleOptions(key, match))
result.push(ruleOptions(key, rule))
match = []
} else {
match.push(rule)
}
})
if (match.length) result.push(ruleOptions(key, match))
}
return result
}
function arrayToRules(array) {
var result = []
for (var i = 0; i < array.length; i++) {
var obj = array[i]
if (obj.include) {
var include = [].concat(obj.include)
for (var j = 0; j < include.length; j++) {
result.push({include: include[j]})
}
continue
}
if (!obj.type) {
throw new Error('Rule has no type: ' + JSON.stringify(obj))
}
result.push(ruleOptions(obj.type, obj))
}
return result
}
function ruleOptions(type, obj) {
if (!isObject(obj)) {
obj = { match: obj }
}
if (obj.include) {
throw new Error('Matching rules cannot also include states')
}
// nb. error and fallback imply lineBreaks
var options = {
defaultType: type,
lineBreaks: !!obj.error || !!obj.fallback,
pop: false,
next: null,
push: null,
error: false,
fallback: false,
value: null,
type: null,
shouldThrow: false,
}
// Avoid Object.assign(), so we support IE9+
for (var key in obj) {
if (hasOwnProperty.call(obj, key)) {
options[key] = obj[key]
}
}
// type transform cannot be a string
if (typeof options.type === 'string' && type !== options.type) {
throw new Error("Type transform cannot be a string (type '" + options.type + "' for token '" + type + "')")
}
// convert to array
var match = options.match
options.match = Array.isArray(match) ? match : match ? [match] : []
options.match.sort(function(a, b) {
return isRegExp(a) && isRegExp(b) ? 0
: isRegExp(b) ? -1 : isRegExp(a) ? +1 : b.length - a.length
})
return options
}
function toRules(spec) {
return Array.isArray(spec) ? arrayToRules(spec) : objectToRules(spec)
}
var defaultErrorRule = ruleOptions('error', {lineBreaks: true, shouldThrow: true})
function compileRules(rules, hasStates) {
var errorRule = null
var fast = Object.create(null)
var fastAllowed = true
var unicodeFlag = null
var groups = []
var parts = []
// If there is a fallback rule, then disable fast matching
for (var i = 0; i < rules.length; i++) {
if (rules[i].fallback) {
fastAllowed = false
}
}
for (var i = 0; i < rules.length; i++) {
var options = rules[i]
if (options.include) {
// all valid inclusions are removed by states() preprocessor
throw new Error('Inheritance is not allowed in stateless lexers')
}
if (options.error || options.fallback) {
// errorRule can only be set once
if (errorRule) {
if (!options.fallback === !errorRule.fallback) {
throw new Error("Multiple " + (options.fallback ? "fallback" : "error") + " rules not allowed (for token '" + options.defaultType + "')")
} else {
throw new Error("fallback and error are mutually exclusive (for token '" + options.defaultType + "')")
}
}
errorRule = options
}
var match = options.match.slice()
if (fastAllowed) {
while (match.length && typeof match[0] === 'string' && match[0].length === 1) {
var word = match.shift()
fast[word.charCodeAt(0)] = options
}
}
// Warn about inappropriate state-switching options
if (options.pop || options.push || options.next) {
if (!hasStates) {
throw new Error("State-switching options are not allowed in stateless lexers (for token '" + options.defaultType + "')")
}
if (options.fallback) {
throw new Error("State-switching options are not allowed on fallback tokens (for token '" + options.defaultType + "')")
}
}
// Only rules with a .match are included in the RegExp
if (match.length === 0) {
continue
}
fastAllowed = false
groups.push(options)
// Check unicode flag is used everywhere or nowhere
for (var j = 0; j < match.length; j++) {
var obj = match[j]
if (!isRegExp(obj)) {
continue
}
if (unicodeFlag === null) {
unicodeFlag = obj.unicode
} else if (unicodeFlag !== obj.unicode && options.fallback === false) {
throw new Error('If one rule is /u then all must be')
}
}
// convert to RegExp
var pat = reUnion(match.map(regexpOrLiteral))
// validate
var regexp = new RegExp(pat)
if (regexp.test("")) {
throw new Error("RegExp matches empty string: " + regexp)
}
var groupCount = reGroups(pat)
if (groupCount > 0) {
throw new Error("RegExp has capture groups: " + regexp + "\nUse (?: … ) instead")
}
// try and detect rules matching newlines
if (!options.lineBreaks && regexp.test('\n')) {
throw new Error('Rule should declare lineBreaks: ' + regexp)
}
// store regex
parts.push(reCapture(pat))
}
// If there's no fallback rule, use the sticky flag so we only look for
// matches at the current index.
//
// If we don't support the sticky flag, then fake it using an irrefutable
// match (i.e. an empty pattern).
var fallbackRule = errorRule && errorRule.fallback
var flags = hasSticky && !fallbackRule ? 'ym' : 'gm'
var suffix = hasSticky || fallbackRule ? '' : '|'
if (unicodeFlag === true) flags += "u"
var combined = new RegExp(reUnion(parts) + suffix, flags)
return {regexp: combined, groups: groups, fast: fast, error: errorRule || defaultErrorRule}
}
function compile(rules) {
var result = compileRules(toRules(rules))
return new Lexer({start: result}, 'start')
}
function checkStateGroup(g, name, map) {
var state = g && (g.push || g.next)
if (state && !map[state]) {
throw new Error("Missing state '" + state + "' (in token '" + g.defaultType + "' of state '" + name + "')")
}
if (g && g.pop && +g.pop !== 1) {
throw new Error("pop must be 1 (in token '" + g.defaultType + "' of state '" + name + "')")
}
}
function compileStates(states, start) {
var all = states.$all ? toRules(states.$all) : []
delete states.$all
var keys = Object.getOwnPropertyNames(states)
if (!start) start = keys[0]
var ruleMap = Object.create(null)
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
ruleMap[key] = toRules(states[key]).concat(all)
}
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var rules = ruleMap[key]
var included = Object.create(null)
for (var j = 0; j < rules.length; j++) {
var rule = rules[j]
if (!rule.include) continue
var splice = [j, 1]
if (rule.include !== key && !included[rule.include]) {
included[rule.include] = true
var newRules = ruleMap[rule.include]
if (!newRules) {
throw new Error("Cannot include nonexistent state '" + rule.include + "' (in state '" + key + "')")
}
for (var k = 0; k < newRules.length; k++) {
var newRule = newRules[k]
if (rules.indexOf(newRule) !== -1) continue
splice.push(newRule)
}
}
rules.splice.apply(rules, splice)
j--
}
}
var map = Object.create(null)
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
map[key] = compileRules(ruleMap[key], true)
}
for (var i = 0; i < keys.length; i++) {
var name = keys[i]
var state = map[name]
var groups = state.groups
for (var j = 0; j < groups.length; j++) {
checkStateGroup(groups[j], name, map)
}
var fastKeys = Object.getOwnPropertyNames(state.fast)
for (var j = 0; j < fastKeys.length; j++) {
checkStateGroup(state.fast[fastKeys[j]], name, map)
}
}
return new Lexer(map, start)
}
function keywordTransform(map) {
// Use a JavaScript Map to map keywords to their corresponding token type
// unless Map is unsupported, then fall back to using an Object:
var isMap = typeof Map !== 'undefined'
var reverseMap = isMap ? new Map : Object.create(null)
var types = Object.getOwnPropertyNames(map)
for (var i = 0; i < types.length; i++) {
var tokenType = types[i]
var item = map[tokenType]
var keywordList = Array.isArray(item) ? item : [item]
keywordList.forEach(function(keyword) {
if (typeof keyword !== 'string') {
throw new Error("keyword must be string (in keyword '" + tokenType + "')")
}
if (isMap) {
reverseMap.set(keyword, tokenType)
} else {
reverseMap[keyword] = tokenType
}
})
}
return function(k) {
return isMap ? reverseMap.get(k) : reverseMap[k]
}
}
/***************************************************************************/
var Lexer = function(states, state) {
this.startState = state
this.states = states
this.buffer = ''
this.stack = []
this.reset()
}
Lexer.prototype.reset = function(data, info) {
this.buffer = data || ''
this.index = 0
this.line = info ? info.line : 1
this.col = info ? info.col : 1
this.queuedToken = info ? info.queuedToken : null
this.queuedText = info ? info.queuedText: "";
this.queuedThrow = info ? info.queuedThrow : null
this.setState(info ? info.state : this.startState)
this.stack = info && info.stack ? info.stack.slice() : []
return this
}
Lexer.prototype.save = function() {
return {
line: this.line,
col: this.col,
state: this.state,
stack: this.stack.slice(),
queuedToken: this.queuedToken,
queuedText: this.queuedText,
queuedThrow: this.queuedThrow,
}
}
Lexer.prototype.setState = function(state) {
if (!state || this.state === state) return
this.state = state
var info = this.states[state]
this.groups = info.groups
this.error = info.error
this.re = info.regexp
this.fast = info.fast
}
Lexer.prototype.popState = function() {
this.setState(this.stack.pop())
}
Lexer.prototype.pushState = function(state) {
this.stack.push(this.state)
this.setState(state)
}
var eat = hasSticky ? function(re, buffer) { // assume re is /y
return re.exec(buffer)
} : function(re, buffer) { // assume re is /g
var match = re.exec(buffer)
// will always match, since we used the |(?:) trick
if (match[0].length === 0) {
return null
}
return match
}
Lexer.prototype._getGroup = function(match) {
var groupCount = this.groups.length
for (var i = 0; i < groupCount; i++) {
if (match[i + 1] !== undefined) {
return this.groups[i]
}
}
throw new Error('Cannot find token type for matched text')
}
function tokenToString() {
return this.value
}
Lexer.prototype.next = function() {
var index = this.index
// If a fallback token matched, we don't need to re-run the RegExp
if (this.queuedGroup) {
var token = this._token(this.queuedGroup, this.queuedText, index)
this.queuedGroup = null
this.queuedText = ""
return token
}
var buffer = this.buffer
if (index === buffer.length) {
return // EOF
}
// Fast matching for single characters
var group = this.fast[buffer.charCodeAt(index)]
if (group) {
return this._token(group, buffer.charAt(index), index)
}
// Execute RegExp
var re = this.re
re.lastIndex = index
var match = eat(re, buffer)
// Error tokens match the remaining buffer
var error = this.error
if (match == null) {
return this._token(error, buffer.slice(index, buffer.length), index)
}
var group = this._getGroup(match)
var text = match[0]
if (error.fallback && match.index !== index) {
this.queuedGroup = group
this.queuedText = text
// Fallback tokens contain the unmatched portion of the buffer
return this._token(error, buffer.slice(index, match.index), index)
}
return this._token(group, text, index)
}
Lexer.prototype._token = function(group, text, offset) {
// count line breaks
var lineBreaks = 0
if (group.lineBreaks) {
var matchNL = /\n/g
var nl = 1
if (text === '\n') {
lineBreaks = 1
} else {
while (matchNL.exec(text)) { lineBreaks++; nl = matchNL.lastIndex }
}
}
var token = {
type: (typeof group.type === 'function' && group.type(text)) || group.defaultType,
value: typeof group.value === 'function' ? group.value(text) : text,
text: text,
toString: tokenToString,
offset: offset,
lineBreaks: lineBreaks,
line: this.line,
col: this.col,
}
// nb. adding more props to token object will make V8 sad!
var size = text.length
this.index += size
this.line += lineBreaks
if (lineBreaks !== 0) {
this.col = size - nl + 1
} else {
this.col += size
}
// throw, if no rule with {error: true}
if (group.shouldThrow) {
var err = new Error(this.formatError(token, "invalid syntax"))
throw err;
}
if (group.pop) this.popState()
else if (group.push) this.pushState(group.push)
else if (group.next) this.setState(group.next)
return token
}
if (typeof Symbol !== 'undefined' && Symbol.iterator) {
var LexerIterator = function(lexer) {
this.lexer = lexer
}
LexerIterator.prototype.next = function() {
var token = this.lexer.next()
return {value: token, done: !token}
}
LexerIterator.prototype[Symbol.iterator] = function() {
return this
}
Lexer.prototype[Symbol.iterator] = function() {
return new LexerIterator(this)
}
}
Lexer.prototype.formatError = function(token, message) {
if (token == null) {
// An undefined token indicates EOF
var text = this.buffer.slice(this.index)
var token = {
text: text,
offset: this.index,
lineBreaks: text.indexOf('\n') === -1 ? 0 : 1,
line: this.line,
col: this.col,
}
}
var numLinesAround = 2
var firstDisplayedLine = Math.max(token.line - numLinesAround, 1)
var lastDisplayedLine = token.line + numLinesAround
var lastLineDigits = String(lastDisplayedLine).length
var displayedLines = lastNLines(
this.buffer,
(this.line - token.line) + numLinesAround + 1
)
.slice(0, 5)
var errorLines = []
errorLines.push(message + " at line " + token.line + " col " + token.col + ":")
errorLines.push("")
for (var i = 0; i < displayedLines.length; i++) {
var line = displayedLines[i]
var lineNo = firstDisplayedLine + i
errorLines.push(pad(String(lineNo), lastLineDigits) + " " + line);
if (lineNo === token.line) {
errorLines.push(pad("", lastLineDigits + token.col + 1) + "^")
}
}
return errorLines.join("\n")
}
Lexer.prototype.clone = function() {
return new Lexer(this.states, this.state)
}
Lexer.prototype.has = function(tokenType) {
return true
}
return {
compile: compile,
states: compileStates,
error: Object.freeze({error: true}),
fallback: Object.freeze({fallback: true}),
keywords: keywordTransform,
}
}));
/***/ }),
/***/ 506:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
// Generated automatically by nearley, version unknown
// http://github.com/Hardmath123/nearley
(function () {
function id(x) { return x[0]; }
// necessary to use keywords to avoid using the `reject` postprocessor which can cause poor perf
// having these as keywords removes ambiguity with `customType` rule
const keywords = [
, "struct"
, "module"
, "enum"
, "const"
, "typedef"
, "union"
, "switch"
, "case"
//types
, "boolean"
, "wstring"
, "string"
, "sequence"
// Boolean types
, "TRUE"
, "FALSE"
// numeric types
, "byte"
, "octet"
, "wchar"
, "char"
, "double"
, "float"
, "int8"
, "uint8"
, "int16"
, "uint16"
, "int32"
, "uint32"
, "int64"
, "uint64"
, "unsigned"
, "short"
, "long"
];
const kwObject = keywords.reduce((obj, w) => {
obj[w] = w;
return obj;
}, {});
const moo = __webpack_require__(694);
// Terminal tokens are in all caps
const lexer = moo.compile({
SPACE: {match: /\s+/, lineBreaks: true},
DECIMALEXP: /(?:(?:\d+\.\d*)|(?:\d*\.\d+)|(?:[0-9]+))[eE](?:[+|-])?[0-9]+/,
DECIMAL: /(?:(?:\d+\.\d*)|(?:\d*\.\d+))/,
INTEGER: /0[xX][0-9a-fA-F]+|\d+/,
COMMENT: /(?:\/\/[^\n]*)|(?:\/\*(?:.|\n)+?\*\/)/,
STRING: {match: /"(?:\\["\\rnu]|[^"\\])*"/, value: x => x.slice(1, -1)}, // remove outside quotes
LCBR: '{',
RCBR: '}',
LBR: '[',
RBR: ']',
LT: '<',
GT: '>',
LPAR: '(',
RPAR: ')',
':': ':',
';': ';',
',': ',',
AT: '@',
PND: '#',
PT: ".",
'/': "/",
SIGN: /[+-]/,
EQ: /=[^\n]*?/,
NAME: {match: /[a-zA-Z_][a-zA-Z0-9_]*(?:\:\:[a-zA-Z][a-zA-Z0-9_]*)*/, type: moo.keywords(kwObject)},
});
// Ignore whitespace and comment tokens
const tokensToIgnore = ['SPACE', 'COMMENT'];
// requires us to override the lexer's next function
lexer.next = (next => () => {
let token;
while ((token = next.call(lexer)) && tokensToIgnore.includes(token.type)) {}
return token;
})(lexer.next);
/*** Utility functions ******/
// also used to parse tokens to strings since they start as an object
function join(d){
return d.join("");
}
// used for combining AST components
function extend(objs) {
return objs.filter(Boolean).reduce((r, p) => ({ ...r, ...p }), {});
}
function noop() {
return null;
}
function getIntOrConstantValue(d) {
const int = parseInt(d);
if(!isNaN(int)) {
return int;
}
// handle %NAME token
return d?.value ? {usesConstant: true, name: d.value} : undefined;
}
var grammar = {
Lexer: lexer,
ParserRules: [
{"name": "main$ebnf$1$subexpression$1$ebnf$1", "symbols": []},
{"name": "main$ebnf$1$subexpression$1$ebnf$1", "symbols": ["main$ebnf$1$subexpression$1$ebnf$1", "importDcl"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "main$ebnf$1$subexpression$1", "symbols": ["main$ebnf$1$subexpression$1$ebnf$1", "definition"]},
{"name": "main$ebnf$1", "symbols": ["main$ebnf$1$subexpression$1"]},
{"name": "main$ebnf$1$subexpression$2$ebnf$1", "symbols": []},
{"name": "main$ebnf$1$subexpression$2$ebnf$1", "symbols": ["main$ebnf$1$subexpression$2$ebnf$1", "importDcl"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "main$ebnf$1$subexpression$2", "symbols": ["main$ebnf$1$subexpression$2$ebnf$1", "definition"]},
{"name": "main$ebnf$1", "symbols": ["main$ebnf$1", "main$ebnf$1$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "main", "symbols": ["main$ebnf$1"], "postprocess": d => {
return d[0].flatMap(inner => inner[1]);
}
},
{"name": "importDcl$subexpression$1", "symbols": [(lexer.has("STRING") ? {type: "STRING"} : STRING)]},
{"name": "importDcl$subexpression$1$ebnf$1", "symbols": []},
{"name": "importDcl$subexpression$1$ebnf$1$subexpression$1", "symbols": [{"literal":"/"}, (lexer.has("NAME") ? {type: "NAME"} : NAME)]},
{"name": "importDcl$subexpression$1$ebnf$1", "symbols": ["importDcl$subexpression$1$ebnf$1", "importDcl$subexpression$1$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "importDcl$subexpression$1", "symbols": [{"literal":"<"}, (lexer.has("NAME") ? {type: "NAME"} : NAME), "importDcl$subexpression$1$ebnf$1", {"literal":"."}, {"literal":"idl"}, {"literal":">"}]},
{"name": "importDcl", "symbols": [{"literal":"#"}, {"literal":"include"}, "importDcl$subexpression$1"], "postprocess": noop},
{"name": "moduleDcl$ebnf$1$subexpression$1", "symbols": ["definition"]},
{"name": "moduleDcl$ebnf$1", "symbols": ["moduleDcl$ebnf$1$subexpression$1"]},
{"name": "moduleDcl$ebnf$1$subexpression$2", "symbols": ["definition"]},
{"name": "moduleDcl$ebnf$1", "symbols": ["moduleDcl$ebnf$1", "moduleDcl$ebnf$1$subexpression$2"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "moduleDcl", "symbols": [{"literal":"module"}, "fieldName", {"literal":"{"}, "moduleDcl$ebnf$1", {"literal":"}"}], "postprocess":
function processModule(d) {
const moduleName = d[1].name;
const defs = d[3];
// need to return array here to keep same signature as processComplexModule
return {
declarator: "module",
name: moduleName,
definitions: defs.flat(1),
};
}
},
{"name": "definition$subexpression$1", "symbols": ["typeDcl"]},
{"name": "definition$subexpression$1", "symbols": ["constantDcl"]},
{"name": "definition$subexpression$1", "symbols": ["moduleDcl"]},
{"name": "definition$subexpression$1", "symbols": ["union"]},
{"name": "definition", "symbols": ["multiAnnotations", "definition$subexpression$1", "semi"], "postprocess": d => {
const annotations = d[0];
const declaration = d[1][0];
return extend([annotations, declaration]);
}},
{"name": "typeDcl$subexpression$1", "symbols": ["struct"]},
{"name": "typeDcl$subexpression$1", "symbols": ["typedef"]},
{"name": "typeDcl$subexpression$1", "symbols": ["enum"]},
{"name": "typeDcl", "symbols": ["typeDcl$subexpression$1"], "postprocess": d => d[0][0]},
{"name": "union", "symbols": [{"literal":"union"}, "fieldName", {"literal":"switch"}, {"literal":"("}, "switchTypedef", {"literal":")"}, {"literal":"{"}, "switchBody", {"literal":"}"}], "postprocess":
(d) => {
const name = d[1].name
const switchType = d[4].type;
const switchBody = d[7];
const allCases = switchBody;
const defaultCase = allCases.find(c => "default" in c);
const cases = allCases.filter(c => ("predicates" in c));
const unionNode = {
declarator: "union",
name,
switchType,
cases,
};
if(defaultCase) {
unionNode.defaultCase = defaultCase.default;
}
return unionNode;
}
},
{"name": "switchTypedef$subexpression$1", "symbols": ["customType"]},
{"name": "switchTypedef$subexpression$1", "symbols": ["numericType"]},
{"name": "switchTypedef$subexpression$1", "symbols": ["booleanType"]},
{"name": "switchTypedef", "symbols": ["switchTypedef$subexpression$1"], "postprocess": d => d[0][0]},
{"name": "switchBody$ebnf$1", "symbols": ["case"]},
{"name": "switchBody$ebnf$1", "symbols": ["switchBody$ebnf$1", "case"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "switchBody", "symbols": ["switchBody$ebnf$1"], "postprocess": d => d.flat(2)},
{"name": "case$ebnf$1", "symbols": ["caseLabel"]},
{"name": "case$ebnf$1", "symbols": ["case$ebnf$1", "caseLabel"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "case", "symbols": ["case$ebnf$1", "elementSpec", {"literal":";"}], "postprocess": d => {
const cases = d[0];
const type = d[1]
const nonDefaultCases = cases.filter(casePredicate => casePredicate !== "default");
const isDefault = cases.length !== nonDefaultCases.length;
const caseArray = []
if(isDefault) {
caseArray.push({default: type});
}
if(nonDefaultCases.length > 0) {
caseArray.push({
predicates: nonDefaultCases,
type,
});
}
return caseArray;
}},
{"name": "caseLabel$subexpression$1", "symbols": [{"literal":"case"}, "constExpression", {"literal":":"}]},
{"name": "caseLabel", "symbols": ["caseLabel$subexpression$1"], "postprocess": (d) => d[0][1]},
{"name": "caseLabel$subexpression$2", "symbols": [{"literal":"default"}, {"literal":":"}]},
{"name": "caseLabel", "symbols": ["caseLabel$subexpression$2"], "postprocess": () => "default"},
{"name": "elementSpec", "symbols": ["typeDeclaratorWithAnnotations"], "postprocess": d => d[0]},
{"name": "enum$ebnf$1", "symbols": []},
{"name": "enum$ebnf$1$subexpression$1", "symbols": [{"literal":","}, "enumFieldName"]},
{"name": "enum$ebnf$1", "symbols": ["enum$ebnf$1", "enum$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "enum", "symbols": [{"literal":"enum"}, "fieldName", {"literal":"{"}, "enumFieldName", "enum$ebnf$1", {"literal":"}"}], "postprocess": d => {
const name = d[1].name;
const firstMember = d[3];
const members = d[4]
.flat(2)
// need to filter out commas
.filter(item => Boolean(item) && item.type !== ",");
return {
declarator: 'enum',
name,
enumerators: [firstMember, ...members],
};
} },
{"name": "enumFieldName", "symbols": ["multiAnnotations", "fieldName"], "postprocess": d => {
const annotations = d[0];
const name = d[1];
return extend([annotations, name]);
} },
{"name": "struct$ebnf$1", "symbols": []},
{"name": "struct$ebnf$1$subexpression$1", "symbols": ["member"]},
{"name": "struct$ebnf$1", "symbols": ["struct$ebnf$1", "struct$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "struct", "symbols": [{"literal":"struct"}, "fieldName", {"literal":"{"}, "struct$ebnf$1", {"literal":"}"}], "postprocess": d => {
const name = d[1].name;
const definitions = d[3].flat(2).filter(def => def !== null);
return {
declarator: 'struct',
name,
definitions,
};
} },
{"name": "typedef", "symbols": [{"literal":"typedef"}, "typeDeclarator"], "postprocess": ([_, definition]) => (
{ declarator: "typedef", ...definition }
)},
{"name": "typeDeclaratorWithAnnotations", "symbols": ["multiAnnotations", "typeDeclarator"], "postprocess": d => {
const annotations = d[0];
const definition = d[1];
return extend([annotations, definition]);
} },
{"name": "typeDeclarator$subexpression$1", "symbols": ["allTypes", "fieldName", "arrayLengths"]},
{"name": "typeDeclarator$subexpression$1", "symbols": ["allTypes", "fieldName"]},
{"name": "typeDeclarator$subexpression$1", "symbols": ["sequenceType", "fieldName"]},
{"name": "typeDeclarator", "symbols": ["typeDeclarator$subexpression$1"], "postprocess": d => extend(d[0])},
{"name": "constantDcl", "symbols": ["constType"], "postprocess": d => d[0]},
{"name": "member", "symbols": ["fieldWithAnnotation", "semi"], "postprocess": d => d[0]},
{"name": "fieldWithAnnotation", "symbols": ["multiAnnotations", "fieldDcl"], "postprocess": d=> {
const annotations = d[0]
const fields = d[1];
const finalDefs = fields.map((def) =>
extend([annotations, def])
);
return finalDefs;
} },
{"name": "fieldDcl$subexpression$1", "symbols": ["allTypes", "multiFieldNames", "arrayLengths"]},
{"name": "fieldDcl$subexpression$1", "symbols": ["allTypes", "multiFieldNames"]},
{"name": "fieldDcl$subexpression$1", "symbols": ["sequenceType", "multiFieldNames"]},
{"name": "fieldDcl", "symbols": ["fieldDcl$subexpression$1"], "postprocess": (d) => {
const names = d[0].splice(1, 1)[0];
// create a definition for each name
const defs = names.map((nameObj) => ({
...extend([...d[0], nameObj]),
declarator: "struct-member"
}));
return defs;
} },
{"name": "multiFieldNames$ebnf$1", "symbols": []},
{"name": "multiFieldNames$ebnf$1$subexpression$1", "symbols": [{"literal":","}, "fieldName"]},
{"name": "multiFieldNames$ebnf$1", "symbols": ["multiFieldNames$ebnf$1", "multiFieldNames$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "multiFieldNames", "symbols": ["fieldName", "multiFieldNames$ebnf$1"], "postprocess":
d => {
const fieldNames = d.flat(2).filter( d => d !== null && d.name);
return fieldNames;
} },
{"name": "multiAnnotations$ebnf$1", "symbols": []},
{"name": "multiAnnotations$ebnf$1", "symbols": ["multiAnnotations$ebnf$1", "annotation"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "multiAnnotations", "symbols": ["multiAnnotations$ebnf$1"], "postprocess":
d => {
return d[0].length > 0 ? {annotations: d[0].reduce((record, annotation) => {
record[annotation.name] = annotation;
return record;
}, {}) } : null;
}
},
{"name": "annotation$ebnf$1$subexpression$1", "symbols": [{"literal":"("}, "annotationParams", {"literal":")"}]},
{"name": "annotation$ebnf$1", "symbols": ["annotation$ebnf$1$subexpression$1"], "postprocess": id},
{"name": "annotation$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}},
{"name": "annotation", "symbols": ["at", (lexer.has("NAME") ? {type: "NAME"} : NAME), "annotation$ebnf$1"], "postprocess": d => {
const annotationName = d[1].value;
const params = d[2] ? d[2][1] : undefined;
if(params == undefined) {
return { type: 'no-params', name: annotationName };
}
// named params in the form of [{<name>: <value>}, ...]
if(Array.isArray(params)) {
const namedParamsRecord = extend(params);
return {
type: 'named-params',
name: annotationName,
namedParams: namedParamsRecord
};
}
// can only be constant param
return { type: "const-param", value: params, name: annotationName };
} },
{"name": "annotationParams$subexpression$1", "symbols": ["multipleNamedAnnotationParams"]},
{"name": "annotationParams$subexpression$1", "symbols": ["constExpression"]},
{"name": "annotationParams", "symbols": ["annotationParams$subexpression$1"], "postprocess": d => d[0][0]},
{"name": "multipleNamedAnnotationParams$ebnf$1", "symbols": []},
{"name": "multipleNamedAnnotationParams$ebnf$1$subexpression$1", "symbols": [{"literal":","}, "namedAnnotationParam"]},
{"name": "multipleNamedAnnotationParams$ebnf$1", "symbols": ["multipleNamedAnnotationParams$ebnf$1", "multipleNamedAnnotationParams$ebnf$1$subexpression$1"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "multipleNamedAnnotationParams", "symbols": ["namedAnnotationParam", "multipleNamedAnnotationParams$ebnf$1"], "postprocess":
d => ([d[0], ...d[1].flatMap(([, param]) => param)]) // returns array
},
{"name": "constExpression", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME)], "postprocess": d =>
// should match `variableAssignment` constant usage structure for consistency
// between named and const annotation types
({usesConstant: true, name: d[0].value})
},
{"name": "constExpression", "symbols": ["literal"], "postprocess": d => d[0].value},
{"name": "namedAnnotationParam$subexpression$1", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME), "assignment"]},
{"name": "namedAnnotationParam", "symbols": ["namedAnnotationParam$subexpression$1"], "postprocess": d => ({[d[0][0].value]: d[0][1].value})},
{"name": "at", "symbols": [{"literal":"@"}], "postprocess": noop},
{"name": "constType$subexpression$1", "symbols": ["constKeyword", "numericType", "fieldName", "floatAssignment", "simple"]},
{"name": "constType$subexpression$1", "symbols": ["constKeyword", "numericType", "fieldName", "intAssignment", "simple"]},
{"name": "constType$subexpression$1", "symbols": ["constKeyword", "stringType", "fieldName", "stringAssignment", "simple"]},
{"name": "constType$subexpression$1", "symbols": ["constKeyword", "booleanType", "fieldName", "booleanAssignment", "simple"]},
{"name": "constType$subexpression$1", "symbols": ["constKeyword", "customType", "fieldName", "variableAssignment", "simple"]},
{"name": "constType", "symbols": ["constType$subexpression$1"], "postprocess": d => {
return extend(d[0]);
} },
{"name": "constKeyword", "symbols": [{"literal":"const"}], "postprocess": d => ({isConstant: true, declarator: "const"})},
{"name": "fieldName", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME)], "postprocess": d => ({name: d[0].value})},
{"name": "sequenceType$ebnf$1$subexpression$1$subexpression$1", "symbols": ["INT"]},
{"name": "sequenceType$ebnf$1$subexpression$1$subexpression$1", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME)]},
{"name": "sequenceType$ebnf$1$subexpression$1", "symbols": [{"literal":","}, "sequenceType$ebnf$1$subexpression$1$subexpression$1"]},
{"name": "sequenceType$ebnf$1", "symbols": ["sequenceType$ebnf$1$subexpression$1"], "postprocess": id},
{"name": "sequenceType$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}},
{"name": "sequenceType", "symbols": [{"literal":"sequence"}, {"literal":"<"}, "allTypes", "sequenceType$ebnf$1", {"literal":">"}], "postprocess": d => {
const arrayUpperBound = d[3] !== null ? getIntOrConstantValue(d[3][1][0]) : undefined;
const typeObj = d[2];
return {
...typeObj,
isArray: true,
arrayUpperBound,
};
}},
{"name": "arrayLengths$ebnf$1", "symbols": ["arrayLength"]},
{"name": "arrayLengths$ebnf$1", "symbols": ["arrayLengths$ebnf$1", "arrayLength"], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "arrayLengths", "symbols": ["arrayLengths$ebnf$1"], "postprocess":
(d) => {
const arrInfo = {isArray: true};
const arrLengthList = d.flat(2).filter((num) => num != undefined);
arrInfo.arrayLengths = arrLengthList;
return arrInfo;
}
},
{"name": "arrayLength$subexpression$1", "symbols": ["INT"]},
{"name": "arrayLength$subexpression$1", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME)]},
{"name": "arrayLength", "symbols": [{"literal":"["}, "arrayLength$subexpression$1", {"literal":"]"}], "postprocess":
([, intOrName]) => (getIntOrConstantValue(intOrName ? intOrName[0] : undefined))
},
{"name": "assignment$subexpression$1", "symbols": ["floatAssignment"]},
{"name": "assignment$subexpression$1", "symbols": ["intAssignment"]},
{"name": "assignment$subexpression$1", "symbols": ["stringAssignment"]},
{"name": "assignment$subexpression$1", "symbols": ["booleanAssignment"]},
{"name": "assignment$subexpression$1", "symbols": ["variableAssignment"]},
{"name": "assignment", "symbols": ["assignment$subexpression$1"], "postprocess": d => d[0][0]},
{"name": "floatAssignment$subexpression$1", "symbols": ["SIGNED_FLOAT"]},
{"name": "floatAssignment$subexpression$1", "symbols": ["FLOAT"]},
{"name": "floatAssignment", "symbols": [(lexer.has("EQ") ? {type: "EQ"} : EQ), "floatAssignment$subexpression$1"], "postprocess": ([, num]) => ({valueText: num[0], value: parseFloat(num[0])})},
{"name": "intAssignment$subexpression$1", "symbols": ["SIGNED_INT"]},
{"name": "intAssignment$subexpression$1", "symbols": ["INT"]},
{"name": "intAssignment", "symbols": [(lexer.has("EQ") ? {type: "EQ"} : EQ), "intAssignment$subexpression$1"], "postprocess": ([, num]) => ({valueText: num[0], value: parseInt(num[0])})},
{"name": "stringAssignment", "symbols": [(lexer.has("EQ") ? {type: "EQ"} : EQ), "STR"], "postprocess": ([, str]) => ({valueText: str, value: str})},
{"name": "booleanAssignment", "symbols": [(lexer.has("EQ") ? {type: "EQ"} : EQ), "BOOLEAN"], "postprocess": ([, bool]) => ({valueText: bool, value: bool === "TRUE"})},
{"name": "variableAssignment", "symbols": [(lexer.has("EQ") ? {type: "EQ"} : EQ), (lexer.has("NAME") ? {type: "NAME"} : NAME)], "postprocess": ([, name]) =>
({
valueText: name.value,
value: {
usesConstant: true,
name: name.value
}
})
},
{"name": "allTypes$subexpression$1", "symbols": ["primitiveTypes"]},
{"name": "allTypes$subexpression$1", "symbols": ["customType"]},
{"name": "allTypes", "symbols": ["allTypes$subexpression$1"], "postprocess": d => d[0][0]},
{"name": "primitiveTypes$subexpression$1", "symbols": ["stringType"]},
{"name": "primitiveTypes$subexpression$1", "symbols": ["numericType"]},
{"name": "primitiveTypes$subexpression$1", "symbols": ["booleanType"]},
{"name": "primitiveTypes", "symbols": ["primitiveTypes$subexpression$1"], "postprocess": d => ({...d[0][0], isComplex: false})},
{"name": "customType", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME)], "postprocess": d => {
const typeName = d[0].value;
// post process will go through and replace typedefs with their actual type
return {type: typeName };
}},
{"name": "stringType$subexpression$1", "symbols": [{"literal":"string"}]},
{"name": "stringType$subexpression$1", "symbols": [{"literal":"wstring"}]},
{"name": "stringType$ebnf$1$subexpression$1$subexpression$1", "symbols": ["INT"]},
{"name": "stringType$ebnf$1$subexpression$1$subexpression$1", "symbols": [(lexer.has("NAME") ? {type: "NAME"} : NAME)]},
{"name": "stringType$ebnf$1$subexpression$1", "symbols": [{"literal":"<"}, "stringType$ebnf$1$subexpression$1$subexpression$1", {"literal":">"}]},
{"name": "stringType$ebnf$1", "symbols": ["stringType$ebnf$1$subexpression$1"], "postprocess": id},
{"name": "stringType$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}},
{"name": "stringType", "symbols": ["stringType$subexpression$1", "stringType$ebnf$1"], "postprocess": d => {
const stringKind = d[0][0].value;
let strLength = undefined;
if(d[1] !== null) {
strLength = getIntOrConstantValue(d[1][1] ? d[1][1][0] : undefined);
}
return {type: stringKind, upperBound: strLength};
} },
{"name": "booleanType", "symbols": [{"literal":"boolean"}], "postprocess": d => ({type: "bool"})},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"byte"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"octet"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"wchar"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"char"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"long"}, {"literal":"double"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"double"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"float"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"int8"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"uint8"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"int16"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"uint16"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"int32"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"uint32"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"int64"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"uint64"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"unsigned"}, {"literal":"short"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"short"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"unsigned"}, {"literal":"long"}, {"literal":"long"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"long"}, {"literal":"long"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"unsigned"}, {"literal":"long"}]},
{"name": "numericType$subexpression$1", "symbols": [{"literal":"long"}]},
{"name": "numericType", "symbols": ["numericType$subexpression$1"], "postprocess": (d) => {
const typeString = d[0].map((t) => t?.value).filter(t => !!t).join(" ");
return { type: typeString };
}
},
{"name": "literal$subexpression$1", "symbols": ["booleanLiteral"]},
{"name": "literal$subexpression$1", "symbols": ["strLiteral"]},
{"name": "literal$subexpression$1", "symbols": ["floatLiteral"]},
{"name": "literal$subexpression$1", "symbols": ["intLiteral"]},
{"name": "literal", "symbols": ["literal$subexpression$1"], "postprocess": d => d[0][0]},
{"name": "booleanLiteral", "symbols": ["BOOLEAN"], "postprocess": d => ({value: d[0] === "TRUE"})},
{"name": "strLiteral", "symbols": ["STR"], "postprocess": d => ({value: d[0]})},
{"name": "floatLiteral$subexpression$1", "symbols": ["SIGNED_FLOAT"]},
{"name": "floatLiteral$subexpression$1", "symbols": ["FLOAT"]},
{"name": "floatLiteral", "symbols": ["floatLiteral$subexpression$1"], "postprocess": d => ({value: parseFloat(d[0][0])})},
{"name": "intLiteral$subexpression$1", "symbols": ["SIGNED_INT"]},
{"name": "intLiteral$subexpression$1", "symbols": ["INT"]},
{"name": "intLiteral", "symbols": ["intLiteral$subexpression$1"], "postprocess": d => ({value: parseInt(d[0][0])})},
{"name": "BOOLEAN$subexpression$1", "symbols": [{"literal":"TRUE"}]},
{"name": "BOOLEAN$subexpression$1", "symbols": [{"literal":"FALSE"}]},
{"name": "BOOLEAN", "symbols": ["BOOLEAN$subexpression$1"], "postprocess": join},
{"name": "STR$ebnf$1", "symbols": [(lexer.has("STRING") ? {type: "STRING"} : STRING)]},
{"name": "STR$ebnf$1", "symbols": ["STR$ebnf$1", (lexer.has("STRING") ? {type: "STRING"} : STRING)], "postprocess": function arrpush(d) {return d[0].concat([d[1]]);}},
{"name": "STR", "symbols": ["STR$ebnf$1"], "postprocess": d => {
return join(d.flat(1).filter(d => d !== null));
}},
{"name": "SIGNED_FLOAT$subexpression$1", "symbols": [{"literal":"+"}]},
{"name": "SIGNED_FLOAT$subexpression$1", "symbols": [{"literal":"-"}]},
{"name": "SIGNED_FLOAT", "symbols": ["SIGNED_FLOAT$subexpression$1", "FLOAT"], "postprocess": join},
{"name": "FLOAT$subexpression$1", "symbols": [(lexer.has("DECIMAL") ? {type: "DECIMAL"} : DECIMAL)]},
{"name": "FLOAT$subexpression$1", "symbols": [(lexer.has("DECIMALEXP") ? {type: "DECIMALEXP"} : DECIMALEXP)]},
{"name": "FLOAT", "symbols": ["FLOAT$subexpression$1"], "postprocess": join},
{"name": "FLOAT$subexpression$2", "symbols": [(lexer.has("DECIMAL") ? {type: "DECIMAL"} : DECIMAL), {"literal":"d"}]},
{"name": "FLOAT", "symbols": ["FLOAT$subexpression$2"], "postprocess": d => d[0][0].value},
{"name": "FLOAT$subexpression$3", "symbols": ["INT", {"literal":"d"}]},
{"name": "FLOAT", "symbols": ["FLOAT$subexpression$3"], "postprocess": d => d[0][0]},
{"name": "SIGNED_INT$subexpression$1", "symbols": [{"literal":"+"}]},
{"name": "SIGNED_INT$subexpression$1", "symbols": [{"literal":"-"}]},
{"name": "SIGNED_INT", "symbols": ["SIGNED_INT$subexpression$1", "INT"], "postprocess": join},
{"name": "INT", "symbols": [(lexer.has("INTEGER") ? {type: "INTEGER"} : INTEGER)], "postprocess": join},
{"name": "semi", "symbols": [{"literal":";"}], "postprocess": noop},
{"name": "simple", "symbols": [], "postprocess": () => ({isComplex: false})}
]
, ParserStart: "main"
}
if ( true&& typeof module.exports !== 'undefined') {
module.exports = grammar;
} else {
window.grammar = grammar;
}
})();
/***/ }),
/***/ 662:
/***/ (function(module) {
(function(root, factory) {
if ( true && module.exports) {
module.exports = factory();
} else {
root.nearley = factory();
}
}(this, function() {
function Rule(name, symbols, postprocess) {
this.id = ++Rule.highestId;
this.name = name;
this.symbols = symbols; // a list of literal | regex class | nonterminal
this.postprocess = postprocess;
return this;
}
Rule.highestId = 0;
Rule.prototype.toString = function(withCursorAt) {
var symbolSequence = (typeof withCursorAt === "undefined")
? this.symbols.map(getSymbolShortDisplay).join(' ')
: ( this.symbols.slice(0, withCursorAt).map(getSymbolShortDisplay).join(' ')
+ " ● "
+ this.symbols.slice(withCursorAt).map(getSymbolShortDisplay).join(' ') );
return this.name + " → " + symbolSequence;
}
// a State is a rule at a position from a given starting point in the input stream (reference)
function State(rule, dot, reference, wantedBy) {
this.rule = rule;
this.dot = dot;
this.reference = reference;
this.data = [];
this.wantedBy = wantedBy;
this.isComplete = this.dot === rule.symbols.length;
}
State.prototype.toString = function() {
return "{" + this.rule.toString(this.dot) + "}, from: " + (this.reference || 0);
};
State.prototype.nextState = function(child) {
var state = new State(this.rule, this.dot + 1, this.reference, this.wantedBy);
state.left = this;
state.right = child;
if (state.isComplete) {
state.data = state.build();
// Having right set here will prevent the right state and its children
// form being garbage collected
state.right = undefined;
}
return state;
};
State.prototype.build = function() {
var children = [];
var node = this;
do {
children.push(node.right.data);
node = node.left;
} while (node.left);