parjs
Version:
A parser-combinator library for JavaScript.
116 lines (115 loc) • 3.84 kB
JavaScript
;
/**
* @module parjs/internal
*/
/** */
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const result_1 = require("./result");
const state_1 = require("./state");
const defaults_1 = __importDefault(require("lodash/defaults"));
const errors_1 = require("../errors");
const combinator_1 = require("./combinators/combinator");
function getErrorLocation(ps) {
let endln = /\r\n|\n|\r/g;
let { input, position } = ps;
let lastPos = 0;
let result;
let line = 0;
while ((result = endln.exec(ps.input))) {
if (result.index > position)
break;
lastPos = result.index + result[0].length;
line++;
}
return {
line,
column: line === 0 ? position : position - lastPos
};
}
/**
* A marker class used for storing the parser's user state.
*/
class ParserUserState {
}
exports.ParserUserState = ParserUserState;
/**
* The base Parjs parser class, which supports only basic parsing operations. Should not be used in user code.
*/
class ParjserBase {
/**
* Apply the parser to the given state.
* @param ps The parsing state.
*/
apply(ps) {
let { position, userState } = ps;
// we do this to verify that the ParsingState's fields have been correctly set by the parser.
ps.kind = result_1.ResultKind.Unknown;
ps.reason = undefined;
ps.value = state_1.UNINITIALIZED_RESULT;
this._apply(ps);
if (ps.kind === result_1.ResultKind.Unknown) {
throw new errors_1.ParserDefinitionError(this.type, "the parser's result kind field has not been set.");
}
if (!ps.isOk) {
ps.value = state_1.FAIL_RESULT;
ps.reason = ps.reason || this.expecting;
}
else if (ps.value === state_1.UNINITIALIZED_RESULT) {
throw new errors_1.ParserDefinitionError(this.type, "a parser must set the result's value field if it succeeds.");
}
if (!ps.isOk) {
if (ps.reason == null) {
throw new errors_1.ParserDefinitionError(this.type, "a failure must have a reason");
}
ps.stack.push(this);
}
else {
ps.stack = [];
}
}
parse(input, initialState) {
if (typeof input !== "string") {
// catches input === undefined, null
throw new Error("input must be a valid string");
}
let userState = defaults_1.default(new ParserUserState(), initialState);
let ps = new state_1.BasicParsingState(input, userState);
ps.initialUserState = initialState;
this.apply(ps);
if (ps.isOk) {
if (ps.position !== input.length) {
ps.kind = result_1.ResultKind.SoftFail;
ps.reason = "parsers did not consume all input";
}
}
if (ps.kind === result_1.ResultKind.Unknown) {
throw new Error("should not happen.");
}
let ret;
if (ps.kind === result_1.ResultKind.Ok) {
return new result_1.ParjsSuccess(ps.value);
}
else {
let trace = {
userState: ps.userState,
position: ps.position,
reason: ps.reason,
input,
get location() {
return getErrorLocation(ps);
},
stackTrace: ps.stack,
kind: ps.kind
};
return new result_1.ParjsFailure(trace);
}
}
pipe(...funcs) {
return combinator_1.pipe(this, ...funcs);
}
}
exports.ParjserBase = ParjserBase;
//# sourceMappingURL=parser.js.map