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

132 lines
3.1 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();
break;
case '+':
case '%':
case '^':
this.readModifier(ch);
break;
case '(':
this.pushState();
break;
case ')':
this.popState();
break;
case '~':
this.addOp('ENTER');
break;
default:
this.addChar(ch);
break;
}
}
if (this.states.length !== 0) {
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) {
var op = parts[1];
var sep = contents.substr(op.length, 1);
var arg = parts[2];
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['^']) {
state.modifiers['^'] = false;
modifier = '^^';
}
state.modifiers[modifier] = true;
};
AutoTypeParser.prototype.resetModifiers = function() {
this.state.modifiers = null;
return this.state.modifiers;
};
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;