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

137 lines
3.2 KiB
JavaScript
Raw Normal View History

2016-04-08 17:40:00 +02:00
'use strict';
var AutoTypeRunner = require('./auto-type-runner');
var AutoTypeParser = function(sequence) {
this.sequence = sequence;
this.ix = 0;
this.states = [];
};
AutoTypeParser.opSepRegex = /[\s:=]+/;
AutoTypeParser.prototype.parse = function() {
var len = this.sequence.length;
this.pushState();
while (this.ix < len) {
var ch = this.sequence[this.ix];
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);
};
AutoTypeParser.prototype.pushState = function() {
this.states.unshift({
modifiers: null,
ops: []
});
};
AutoTypeParser.prototype.popState = function() {
if (this.states.length <= 1) {
throw 'Unexpected ")" at index ' + this.ix;
}
var state = this.states.shift();
this.addState(state);
};
AutoTypeParser.prototype.state = function() {
return this.states[0];
};
AutoTypeParser.prototype.readOp = function() {
var toIx = this.sequence.indexOf('}', this.ix + 2);
if (toIx < 0) {
throw 'Mismatched "{" at index ' + this.ix;
}
var contents = this.sequence.substring(this.ix + 1, toIx);
this.ix = toIx + 1;
if (contents.length === 1) {
this.addChar(contents);
return;
}
var parts = contents.split(AutoTypeParser.opSepRegex, 2);
if (parts.length > 1 && parts[0].length && parts[1].length) {
2016-04-08 22:33:07 +02:00
var op = parts[0];
2016-04-08 17:40:00 +02:00
var sep = contents.substr(op.length, 1);
2016-04-08 22:33:07 +02:00
var arg = parts[1];
2016-04-08 17:40:00 +02:00
this.addOp(op, sep, arg);
} else {
this.addOp(contents);
}
};
AutoTypeParser.prototype.readModifier = function(modifier) {
var state = this.state();
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;
};
AutoTypeParser.prototype.resetModifiers = function() {
2016-04-08 22:33:07 +02:00
var state = this.state();
var modifiers = state.modifiers;
state.modifiers = null;
return modifiers;
2016-04-08 17:40:00 +02:00
};
AutoTypeParser.prototype.addState = function(state) {
this.state().ops.push({
type: 'group',
value: state.ops,
mod: this.resetModifiers()
});
};
AutoTypeParser.prototype.addChar = function(ch) {
this.state().ops.push({
type: 'text',
value: ch,
mod: this.resetModifiers()
});
};
AutoTypeParser.prototype.addOp = function(op, sep, arg) {
this.state().ops.push({
type: 'op',
value: op,
mod: this.resetModifiers(),
sep: sep,
arg: arg
});
};
module.exports = AutoTypeParser;