
org.textmapper.tool.templates.js_parser.ltp Maven / Gradle / Ivy
${template unit-}
${call nonterminalsInterface-}
${opts.module}.Parser = function(errorHandler) {
this.errorHandler = errorHandler;
this.tmHead = 0;
this.tmStack = [];
this.tmNext = null;
this.tmLexer = null;
};
${opts.module}.Parser.prototype = {
${call parserTables}
${call action}
${call tmGoto}
${call tmParse}
${if self->hasRecovering()-}
${call restore}
${end-}
${call shift}
${call reduce}
${if self->hasRecovering()-}
/**
* disposes symbol dropped by error recovery mechanism
*/
dispose: function(value) {
},
${end-}
${if opts.genCleanup-}
/**
* cleans node removed from the stack
*/
cleanup: function(value) {
},
${end-}
${if self->util.needFinalState()-}
${call customParseRoutines}
${end-}
${call js.classcode-}
${call applyRule-}
};
${end}
${template nonterminalsInterface-}
${opts.module}.Nonterminals = {
${for i in [syntax.terminals, parser.nsyms - 1] separator ',\n'-}
${syntax.symbols[i].id->js.escapeJsReserved()}: ${i-}
${end}
};
${end}
${template action-}
/**
* -3-n Lookahead (state id)
* -2 Error
* -1 Shift
* 0..n Reduce (rule index)
*/
action: function(state, symbol) {
${if self->needActionsTable()-}
var p;
if (this.tmAction[state] < -2) {
${if self->lazyNext()-}
if (symbol === ${opts.module}.Lexer.Tokens.Unavailable_) {
return -3 - state;
}
${end-}
for (p = -this.tmAction[state] - 3; this.tmLalr[p] >= 0; p += 2) {
if (this.tmLalr[p] === symbol) {
break;
}
}
return this.tmLalr[p + 1];
}
${end-}
return this.tmAction[state];
},
${end}
${template tmGoto-}
tmGoto: function(state, symbol) {
var min = this.lapg_sym_goto[symbol], max = this.lapg_sym_goto[symbol + 1] - 1;
var i, e;
while (min <= max) {
e = (min + max) >> 1;
i = this.lapg_sym_from[e];
if (i == state) {
return this.lapg_sym_to[e];
} else if (i < state) {
min = e + 1;
} else {
max = e - 1;
}
}
return -1;
},
${end}
${template tmParse-}
parse: function(lexer${if self->util.needInitialState()}, initialState${end}${if self->util.needFinalState()}, finalState${end
}${if self->hasNoEoiInputs() && self->hasEoiInputs()}, noEoi${end}) {
this.tmLexer = lexer;
this.tmStack = [];
this.tmHead = 0;
${if self->hasRecovering()} var tmShiftsAfterError = 4;
${end-}
this.tmStack[0] = {state: ${self->util.needInitialState() ? 'initialState' : 0}};
this.tmNext = lexer.next();
while (this.tmStack[this.tmHead].state != ${self->util.needFinalState() ? 'finalState' : parser.statesCount-1}) {
var action = this.action(this.tmStack[this.tmHead].state, ${if self->lazyNext()}this.tmNext == null ? ${opts.module}.Lexer.Tokens.Unavailable_ : ${end}this.tmNext.symbol);
${if self->lazyNext()-}
if (action <= -3 && this.tmNext == null) {
this.tmNext = this.tmLexer.next();
action = this.action(this.tmStack[this.tmHead].state, this.tmNext.symbol);
}
${end-}
if (action >= 0) {
this.reduce(action);
} else if (action == -1) {
this.shift(${if self->hasNoEoiInputs() && self->hasEoiInputs()}noEoi${end});
${if self->hasRecovering()} tmShiftsAfterError++;
${end-}
}
if (action == -2 || this.tmStack[this.tmHead].state == -1) {
${if self->hasRecovering()-}
if (this.restore()) {
if (tmShiftsAfterError >= 4) {
this.errorHandler("syntax error before line " + lexer.tokenLine${if opts.positions.contains(
'column')} + ", column " + this.tmNext.column${end}${call js.err_location('this.tmNext', 'lexer')});
}
if (tmShiftsAfterError <= 1) {
this.tmNext = lexer.next();
}
tmShiftsAfterError = 0;
continue;
}
if (this.tmHead < 0) {
this.tmHead = 0;
this.tmStack[0] = {state: ${self->util.needInitialState() ? 'initialState' : 0}};
}
${end-}
break;
}
}
if (this.tmStack[this.tmHead].state != ${self->util.needFinalState() ? 'finalState' : parser.statesCount-1}) {
${if self->hasRecovering()-}
if (tmShiftsAfterError >= 4) {
${else-}
${end} this.errorHandler("syntax error before line " + lexer.tokenLine${
if opts.positions.contains('column')} + ", column " + ${
if self->lazyNext()}(this.tmNext == null ? lexer.currColumn : this.tmNext.column)${else}this.tmNext.column${
end}${end}${(self->lazyNext() ? self->js.err_location_safe('this.tmNext', 'lexer')
: self->js.err_location('this.tmNext', 'lexer'))});
${if self->hasRecovering()-}
}
${end-}
throw new Error("syntax error");
}
return this.tmStack[${
self->hasNoEoiInputs() && self->hasEoiInputs()
? 'noEoi ? this.tmHead : this.tmHead - 1' :
self->hasNoEoiInputs()
? 'this.tmHead'
: 'this.tmHead - 1'
}].value;
},
${end}
${template restore-}
restore: function() {
${if self->lazyNext()-}
if (this.tmNext == null) {
this.tmNext = this.tmLexer.next();
}
${end-}
if (this.tmNext.symbol == 0) {
return false;
}
while (this.tmHead >= 0 && this.tmGoto(this.tmStack[this.tmHead].state, ${self->errorToken()}) == -1) {
this.dispose(this.tmStack[this.tmHead]);
this.tmStack[this.tmHead] = null;
this.tmHead--;
}
if (this.tmHead >= 0) {
this.tmStack[++this.tmHead] = {
symbol: ${self->errorToken()},
state: this.tmGoto(this.tmStack[this.tmHead - 1].state, ${self->errorToken()}),
${foreach l in self->util.locationList()-}
${l}: this.tmNext.${l},
${end-}
value: null
};
return true;
}
return false;
},
${end}
${template shift-}
shift: function(${if self->hasNoEoiInputs() && self->hasEoiInputs()}lazy${end}) {
${if self->lazyNext()-}
if (this.tmNext == null) {
this.tmNext = this.tmLexer.next();
}
${end-}
this.tmStack[++this.tmHead] = this.tmNext;
this.tmStack[this.tmHead].state = this.tmGoto(this.tmStack[this.tmHead - 1].state, this.tmNext.symbol);
${call debugShift-}
if (this.tmStack[this.tmHead].state != -1 && this.tmNext.symbol != 0) {
this.tmNext = ${
self->hasNoEoiInputs() && self->hasEoiInputs()
? 'lazy ? null : this.tmLexer.next()' :
self->hasNoEoiInputs()
? 'null'
: 'this.tmLexer.next()'
};
}
},
${end}
${template reduce-}
reduce: function(rule) {
var tmLeft = {
value: (this.tmRuleLen[rule] != 0) ? this.tmStack[this.tmHead + 1 - this.tmRuleLen[rule]].value : null,
symbol: this.tmRuleSymbol[rule],
state: 0
};
${call debugReduce-}
${if opts.positions.contains('line') || opts.positions.contains('offset') || opts.positions.contains('column')-}
var startsym = (this.tmRuleLen[rule] != 0) ? this.tmStack[this.tmHead + 1 - this.tmRuleLen[rule]] : this.tmNext;
${if opts.positions.contains('line')-}
tmLeft.line = ${if self->lazyNext()}startsym == null ? this.tmLexer.currLine : ${end}startsym.line;
${end-}
${if opts.positions.contains('column')-}
tmLeft.column = ${if self->lazyNext()}startsym == null ? this.tmLexer.currColumn : ${end}startsym.column;
${end-}
${if opts.positions.contains('offset')-}
tmLeft.offset = ${if self->lazyNext()}startsym == null ? this.tmLexer.currOffset : ${end}startsym.offset;
${end-}
${end-}
${if opts.endpositions.contains('line')-}
tmLeft.endline = (this.tmRuleLen[rule] != 0) ? this.tmStack[this.tmHead].endline : ${
if self->lazyNext()}this.tmNext == null ? this.tmLexer.currLine : ${end}this.tmNext.line;
${end-}
${if opts.endpositions.contains('column')-}
tmLeft.endcolumn = (this.tmRuleLen[rule] != 0) ? this.tmStack[this.tmHead].endcolumn : ${
if self->lazyNext()}this.tmNext == null ? this.tmLexer.currColumn : ${end}this.tmNext.column;
${end-}
${if opts.endpositions.contains('offset')-}
tmLeft.endoffset = (this.tmRuleLen[rule] != 0) ? this.tmStack[this.tmHead].endoffset : ${
if self->lazyNext()}this.tmNext == null ? this.tmLexer.currOffset : ${end}this.tmNext.offset;
${end-}
this.applyRule(tmLeft, rule, this.tmRuleLen[rule]);
for (var e = this.tmRuleLen[rule]; e > 0; e--) {
${if opts.genCleanup-}
this.cleanup(this.tmStack[this.tmHead]);
${end-}
this.tmStack[this.tmHead--] = null;
}
this.tmStack[++this.tmHead] = tmLeft;
this.tmStack[this.tmHead].state = this.tmGoto(this.tmStack[this.tmHead - 1].state, tmLeft.symbol);
},
${end}
${template customParseRoutines-}
${foreach inp in syntax.input}
parse${util.toFirstUpper(inp.target.id)}: function(lexer) {
return this.parse(lexer${if self->util.needInitialState()}, ${index}${end}, ${parser.finalStates[index]}${
if self->hasNoEoiInputs() && self->hasEoiInputs()}, ${inp.hasEoi() ? 'false' : 'true'}${end});
},
${end-}
${end}
${template applyRule-}
applyRule: function(tmLeft, ruleIndex, ruleLength) {
${if syntax.rules.exists(r|r.codeTemplate())-}
switch (ruleIndex) {
${foreach rule in syntax.rules-}
${if rule.codeTemplate()-}
case ${rule.getIndex()}: // ${rule}
${rule.code()-}
${if opts.breaks } break;$/
${end-}
${end-}
}
${end-}
}
${end}
${template parserAction-}
${if codeTemplate()-}
${eval codeTemplate()}
${end-}
${end}
${template debugShift-}
if (${context.opts.module}.DEBUG_SYNTAX) {
console.log("shift: " + this.tmSymbolNames[this.tmNext.symbol] + " (" + this.tmLexer.token + ")");
}
${end}
${template debugReduce-}
if (${context.opts.module}.DEBUG_SYNTAX) {
console.log("reduce to " + this.tmSymbolNames[this.tmRuleSymbol[rule]]);
}
${end}
${query needActionsTable() = parser.lalr.size() > 0}
${template parserTables-}
tmAction: [
${util.format(parser.action, 16, 2)}
],
${if self->needActionsTable()-}
tmLalr: [
${util.format(parser.lalr, 16, 2)}
],
${end-}
lapg_sym_goto: [
${util.format(parser.symGoto, 16, 2)}
],
lapg_sym_from: [
${util.format(parser.symFrom, 16, 2)}
],
lapg_sym_to: [
${util.format(parser.symTo, 16, 2)}
],
tmRuleLen: [
${util.format(parser.ruleLength, 16, 2)}
],
tmRuleSymbol: [
${util.format(parser.left, 16, 2)}
],
tmSymbolNames: [
${foreach s in parser.symbols separator ',\n'-}
"${s.name}"${end}
],
${if syntax.rules.exists(x|x.getSource() is org.textmapper.lapg.api.rule.RhsSequence && x.getSource().name)}
tmRules: [
${foreach rule in syntax.rules.collect(rule|rule.getSource() is org.textmapper.lapg.api.rule.RhsSequence
&& rule.getSource().name) separator ',\n'-}
// ${rule}
${util.uniqueId(rule.getLeft().id + '_' + rule.getSource().name, '__rules__')}: ${rule.getIndex()-}
${end-}
],
${end-}
${end}
${cached query hasRecovering() = syntax.error}
${cached query errorToken() = syntax.error.index}
${cached query hasNoEoiInputs() = syntax.input.exists(x|!x.hasEoi()) }
${cached query hasEoiInputs() = syntax.input.exists(x|x.hasEoi()) }
${cached query lazyNext() = self->hasNoEoiInputs() }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy