All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.textmapper.tool.templates.js_parser.ltp Maven / Gradle / Ivy

There is a newer version: 0.9.5
Show newest version
${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