add ":" to param transitions, fix parse loop and tests

This commit is contained in:
Jörg Breitbart
2019-06-17 21:54:51 +02:00
parent cec1aa3f33
commit c5385a640d
2 changed files with 66 additions and 36 deletions
+27 -9
View File
@@ -3,11 +3,12 @@
* @license MIT
*/
import { IDcsHandler, IParsingState } from 'common/parser/Types';
import { IDcsHandler, IParsingState, IParams } from 'common/parser/Types';
import { EscapeSequenceParser, TransitionTable, VT500_TRANSITION_TABLE } from 'common/parser/EscapeSequenceParser';
import * as chai from 'chai';
import { StringToUtf32, stringFromCodePoint } from 'common/input/TextDecoder';
import { ParserState } from 'common/parser/Constants';
import { Params } from 'common/parser/Params';
function r(a: number, b: number): string[] {
let c = b - a;
@@ -27,10 +28,13 @@ class TestEscapeSequenceParser extends EscapeSequenceParser {
this._osc = value;
}
public get params(): number[] {
return this._params;
return this._params.toArray() as number[];
}
public set params(value: number[]) {
this._params = value;
this._params = Params.fromArray(value);
}
public get realParams(): IParams {
return this._params;
}
public get collect(): string {
return this._collect;
@@ -562,16 +566,17 @@ describe('EscapeSequenceParser', function (): void {
testTerminal.clear();
}
});
it('trans CSI_ENTRY --> CSI_IGNORE', function (): void {
it('trans CSI_ENTRY --> CSI_PARAM for ":" (0x3a)', function (): void {
parser.reset();
parser.currentState = ParserState.CSI_ENTRY;
parse(parser, '\x3a');
chai.expect(parser.currentState).equal(ParserState.CSI_IGNORE);
chai.expect(parser.currentState).equal(ParserState.CSI_PARAM);
parser.reset();
});
/*
it('trans CSI_PARAM --> CSI_IGNORE', function (): void {
parser.reset();
const chars = ['\x3a', '\x3c', '\x3d', '\x3e', '\x3f'];
const chars = ['\x3c', '\x3d', '\x3e', '\x3f'];
for (let i = 0; i < chars.length; ++i) {
parser.currentState = ParserState.CSI_PARAM;
parse(parser, '\x3b' + chars[i]);
@@ -580,6 +585,19 @@ describe('EscapeSequenceParser', function (): void {
parser.reset();
}
});
*/
it('trans CSI_PARAM --> CSI_IGNORE', function (): void {
parser.reset();
const chars = ['\x3c', '\x3d', '\x3e', '\x3f'];
for (let i = 0; i < chars.length; ++i) {
chai.expect(parser.params).eql([0]);
parser.currentState = ParserState.CSI_PARAM;
parse(parser, '\x3b' + chars[i]);
chai.expect(parser.currentState).equal(ParserState.CSI_IGNORE);
// chai.expect(parser.params).eql([0, 0]);
parser.reset();
}
});
it('trans CSI_INTERMEDIATE --> CSI_IGNORE', function (): void {
parser.reset();
const chars = r(0x30, 0x40);
@@ -785,16 +803,16 @@ describe('EscapeSequenceParser', function (): void {
chai.expect(parser.params).eql([0, 0]);
parser.reset();
});
it('trans DCS_ENTRY --> DCS_IGNORE', function (): void {
it('trans DCS_ENTRY --> DCS_PARAM for ":" (0x3a)', function (): void {
parser.reset();
parser.currentState = ParserState.DCS_ENTRY;
parse(parser, '\x3a');
chai.expect(parser.currentState).equal(ParserState.DCS_IGNORE);
chai.expect(parser.currentState).equal(ParserState.DCS_PARAM);
parser.reset();
});
it('trans DCS_PARAM --> DCS_IGNORE', function (): void {
parser.reset();
const chars = ['\x3a', '\x3c', '\x3d', '\x3e', '\x3f'];
const chars = ['\x3c', '\x3d', '\x3e', '\x3f'];
for (let i = 0; i < chars.length; ++i) {
parser.currentState = ParserState.DCS_PARAM;
parse(parser, '\x3b' + chars[i]);
+39 -27
View File
@@ -9,6 +9,7 @@ import { Disposable } from 'common/Lifecycle';
import { utf32ToString } from 'common/input/TextDecoder';
import { IDisposable } from 'common/Types';
import { fill } from 'common/TypedArrayUtils';
import { Params } from 'common/parser/Params';
interface IHandlerCollection<T> {
[key: string]: T[];
@@ -143,17 +144,14 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
// csi entries
table.add(0x5b, ParserState.ESCAPE, ParserAction.CLEAR, ParserState.CSI_ENTRY);
table.addMany(r(0x40, 0x7f), ParserState.CSI_ENTRY, ParserAction.CSI_DISPATCH, ParserState.GROUND);
table.addMany(r(0x30, 0x3a), ParserState.CSI_ENTRY, ParserAction.PARAM, ParserState.CSI_PARAM);
table.add(0x3b, ParserState.CSI_ENTRY, ParserAction.PARAM, ParserState.CSI_PARAM);
table.addMany(r(0x30, 0x3c), ParserState.CSI_ENTRY, ParserAction.PARAM, ParserState.CSI_PARAM);
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_PARAM);
table.addMany(r(0x30, 0x3a), ParserState.CSI_PARAM, ParserAction.PARAM, ParserState.CSI_PARAM);
table.add(0x3b, ParserState.CSI_PARAM, ParserAction.PARAM, ParserState.CSI_PARAM);
table.addMany(r(0x30, 0x3c), ParserState.CSI_PARAM, ParserAction.PARAM, ParserState.CSI_PARAM);
table.addMany(r(0x40, 0x7f), ParserState.CSI_PARAM, ParserAction.CSI_DISPATCH, ParserState.GROUND);
table.addMany([0x3a, 0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_IGNORE);
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.CSI_PARAM, ParserAction.IGNORE, ParserState.CSI_IGNORE);
table.addMany(r(0x20, 0x40), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
table.add(0x7f, ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
table.addMany(r(0x40, 0x7f), ParserState.CSI_IGNORE, ParserAction.IGNORE, ParserState.GROUND);
table.add(0x3a, ParserState.CSI_ENTRY, ParserAction.IGNORE, ParserState.CSI_IGNORE);
table.addMany(r(0x20, 0x30), ParserState.CSI_ENTRY, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
table.addMany(r(0x20, 0x30), ParserState.CSI_INTERMEDIATE, ParserAction.COLLECT, ParserState.CSI_INTERMEDIATE);
table.addMany(r(0x30, 0x40), ParserState.CSI_INTERMEDIATE, ParserAction.IGNORE, ParserState.CSI_IGNORE);
@@ -173,9 +171,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
table.add(0x7f, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
table.addMany(r(0x1c, 0x20), ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_ENTRY);
table.addMany(r(0x20, 0x30), ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
table.add(0x3a, ParserState.DCS_ENTRY, ParserAction.IGNORE, ParserState.DCS_IGNORE);
table.addMany(r(0x30, 0x3a), ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM);
table.add(0x3b, ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM);
table.addMany(r(0x30, 0x3c), ParserState.DCS_ENTRY, ParserAction.PARAM, ParserState.DCS_PARAM);
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_ENTRY, ParserAction.COLLECT, ParserState.DCS_PARAM);
table.addMany(EXECUTABLES, ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
table.addMany(r(0x20, 0x80), ParserState.DCS_IGNORE, ParserAction.IGNORE, ParserState.DCS_IGNORE);
@@ -183,9 +179,8 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
table.addMany(EXECUTABLES, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
table.add(0x7f, ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
table.addMany(r(0x1c, 0x20), ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_PARAM);
table.addMany(r(0x30, 0x3a), ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM);
table.add(0x3b, ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM);
table.addMany([0x3a, 0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_IGNORE);
table.addMany(r(0x30, 0x3c), ParserState.DCS_PARAM, ParserAction.PARAM, ParserState.DCS_PARAM);
table.addMany([0x3c, 0x3d, 0x3e, 0x3f], ParserState.DCS_PARAM, ParserAction.IGNORE, ParserState.DCS_IGNORE);
table.addMany(r(0x20, 0x30), ParserState.DCS_PARAM, ParserAction.COLLECT, ParserState.DCS_INTERMEDIATE);
table.addMany(EXECUTABLES, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
table.add(0x7f, ParserState.DCS_INTERMEDIATE, ParserAction.IGNORE, ParserState.DCS_INTERMEDIATE);
@@ -236,7 +231,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
// buffers over several parse calls
protected _osc: string;
protected _params: number[];
protected _params: Params;
protected _collect: string;
// handler lookup containers
@@ -264,7 +259,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
this.initialState = ParserState.GROUND;
this.currentState = this.initialState;
this._osc = '';
this._params = [0];
this._params = new Params();
this._params.addParam(0);
this._collect = '';
this.precedingCodepoint = 0;
@@ -394,7 +390,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
reset(): void {
this.currentState = this.initialState;
this._osc = '';
this._params = [0];
this._params.reset();
this._params.addParam(0);
this._collect = '';
this._activeDcsHandler = null;
this.precedingCodepoint = 0;
@@ -418,7 +415,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
let currentState = this.currentState;
let osc = this._osc;
let collect = this._collect;
let params = this._params;
const params = this._params;
const table: Uint8Array = this.TRANSITIONS.table;
let dcsHandler: IDcsHandler | null = this._activeDcsHandler;
let callback: Function | null = null;
@@ -472,7 +469,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
currentState,
osc,
collect,
params,
params: params.toArray() as number[],
abort: false
});
if (inject.abort) return;
@@ -488,20 +485,32 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
let j = handlers ? handlers.length - 1 : -1;
for (; j >= 0; j--) {
// undefined or true means success and to stop bubbling
if (handlers[j](params, collect) !== false) {
if (handlers[j](params.toArray() as number[], collect) !== false) {
break;
}
}
if (j < 0) {
this._csiHandlerFb(collect, params, code);
this._csiHandlerFb(collect, params.toArray() as number[], code);
}
break;
case ParserAction.PARAM:
// inner loop: digits (0x30 - 0x39) and ; (0x3b)
// inner loop: digits (0x30 - 0x39) and ; (0x3b) and : (0x3a)
let isSub = false;
do {
if (code === 0x3b) params.push(0);
else params[params.length - 1] = params[params.length - 1] * 10 + code - 48;
} while (++i < length && (code = data[i]) > 0x2f && (code < 0x3a || code === 0x3b));
switch (code) {
case 0x3b:
params.addParam(0);
isSub = false;
break;
case 0x3a:
params.addSubParam(-1);
isSub = true;
break;
default: // 0x30 - 0x39
if (isSub) params.addSubParamDigit(code - 48);
else params.addParamDigit(code - 48);
}
} while (++i < length && (code = data[i]) > 0x2f && code < 0x3c);
i--;
break;
case ParserAction.COLLECT:
@@ -515,14 +524,15 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
break;
case ParserAction.CLEAR:
osc = '';
params = [0];
params.reset();
params.addParam(0);
collect = '';
break;
case ParserAction.DCS_HOOK:
this.precedingCodepoint = 0;
dcsHandler = this._dcsHandlers[collect + String.fromCharCode(code)];
if (!dcsHandler) dcsHandler = this._dcsHandlerFb;
dcsHandler.hook(collect, params, code);
dcsHandler.hook(collect, params.toArray() as number[], code);
break;
case ParserAction.DCS_PUT:
// inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f
@@ -544,7 +554,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
}
if (code === 0x1b) transition |= ParserState.ESCAPE;
osc = '';
params = [0];
params.reset();
params.addParam(0);
collect = '';
break;
case ParserAction.OSC_START:
@@ -590,7 +601,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
}
if (code === 0x1b) transition |= ParserState.ESCAPE;
osc = '';
params = [0];
params.reset();
params.addParam(0);
collect = '';
break;
}