keeweb/app/scripts/auto-type/auto-type-parser.js

128 lines
3.1 KiB
JavaScript
Raw Normal View History

2019-09-15 14:16:32 +02:00
import { AutoTypeRunner } from 'auto-type/auto-type-runner';
2016-04-08 17:40:00 +02:00
2020-06-01 16:53:51 +02:00
const AutoTypeParser = function (sequence) {
2016-04-08 17:40:00 +02:00
this.sequence = sequence;
this.ix = 0;
this.states = [];
};
AutoTypeParser.opRegex = /^(.*?)(?:([\s:=])[\s:=]*(.*))?$/;
2016-04-08 17:40:00 +02:00
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.parse = function () {
2017-01-31 07:50:28 +01:00
const len = this.sequence.length;
2016-04-08 17:40:00 +02:00
this.pushState();
while (this.ix < len) {
2017-01-31 07:50:28 +01:00
const ch = this.sequence[this.ix];
2016-04-08 17:40:00 +02:00
switch (ch) {
case '{':
this.readOp();
2016-04-08 22:33:07 +02:00
continue;
2016-04-08 17:40:00 +02:00
case '+':
case '%':
case '^':
this.readModifier(ch);
break;
case '(':
this.pushState();
break;
case ')':
this.popState();
break;
2016-04-09 08:29:30 +02:00
case ' ':
break;
2016-04-08 17:40:00 +02:00
case '~':
2016-04-09 14:55:27 +02:00
this.addOp('enter');
2016-04-08 17:40:00 +02:00
break;
default:
this.addChar(ch);
break;
}
2016-04-08 22:33:07 +02:00
this.ix++;
2016-04-08 17:40:00 +02:00
}
2016-04-08 22:33:07 +02:00
if (this.states.length !== 1) {
2016-04-08 17:40:00 +02:00
throw 'Groups count mismatch';
}
return new AutoTypeRunner(this.state().ops);
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.pushState = function () {
2016-04-08 17:40:00 +02:00
this.states.unshift({
modifiers: null,
ops: []
});
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.popState = function () {
2016-04-08 17:40:00 +02:00
if (this.states.length <= 1) {
throw 'Unexpected ")" at index ' + this.ix;
}
2017-01-31 07:50:28 +01:00
const state = this.states.shift();
2016-04-08 17:40:00 +02:00
this.addState(state);
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.state = function () {
2016-04-08 17:40:00 +02:00
return this.states[0];
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.readOp = function () {
2017-01-31 07:50:28 +01:00
const toIx = this.sequence.indexOf('}', this.ix + 2);
2016-04-08 17:40:00 +02:00
if (toIx < 0) {
throw 'Mismatched "{" at index ' + this.ix;
}
2017-01-31 07:50:28 +01:00
const contents = this.sequence.substring(this.ix + 1, toIx);
2016-04-08 17:40:00 +02:00
this.ix = toIx + 1;
if (contents.length === 1) {
this.addChar(contents);
return;
}
const [, op, sep, arg] = contents.match(AutoTypeParser.opRegex);
this.addOp(op, sep, arg);
2016-04-08 17:40:00 +02:00
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.readModifier = function (modifier) {
2017-01-31 07:50:28 +01:00
const state = this.state();
2016-04-08 17:40:00 +02:00
if (!state.modifiers) {
state.modifiers = {};
}
if (modifier === '^' && state.modifiers['^']) {
2016-04-08 22:33:07 +02:00
delete state.modifiers['^'];
2016-04-08 17:40:00 +02:00
modifier = '^^';
}
state.modifiers[modifier] = true;
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.resetModifiers = function () {
2017-01-31 07:50:28 +01:00
const state = this.state();
const modifiers = state.modifiers;
2016-04-08 22:33:07 +02:00
state.modifiers = null;
return modifiers;
2016-04-08 17:40:00 +02:00
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.addState = function (state) {
2016-04-08 17:40:00 +02:00
this.state().ops.push({
type: 'group',
value: state.ops,
mod: this.resetModifiers()
});
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.addChar = function (ch) {
2016-04-08 17:40:00 +02:00
this.state().ops.push({
type: 'text',
value: ch,
mod: this.resetModifiers()
});
};
2020-06-01 16:53:51 +02:00
AutoTypeParser.prototype.addOp = function (op, sep, arg) {
2016-04-08 17:40:00 +02:00
this.state().ops.push({
type: 'op',
value: op,
mod: this.resetModifiers(),
2019-08-18 10:17:09 +02:00
sep,
arg
2016-04-08 17:40:00 +02:00
});
};
2019-09-15 14:16:32 +02:00
export { AutoTypeParser };