Replace array with immutable stack

This commit is contained in:
Alex Dima 2020-09-21 10:56:39 +02:00
parent 77add4162b
commit bb6231ad91
No known key found for this signature in database
GPG key ID: 6E58D7B045760DA0

View file

@ -10,7 +10,7 @@ export function createTokenizationSupport(
supportComments: boolean supportComments: boolean
): languages.TokensProvider { ): languages.TokensProvider {
return { return {
getInitialState: () => new JSONState(null, null, false, []), getInitialState: () => new JSONState(null, null, false, null),
tokenize: (line, state, offsetDelta?, stopAtOffset?) => tokenize: (line, state, offsetDelta?, stopAtOffset?) =>
tokenize( tokenize(
supportComments, supportComments,
@ -34,23 +34,67 @@ export const TOKEN_PROPERTY_NAME = 'string.key.json';
export const TOKEN_COMMENT_BLOCK = 'comment.block.json'; export const TOKEN_COMMENT_BLOCK = 'comment.block.json';
export const TOKEN_COMMENT_LINE = 'comment.line.json'; export const TOKEN_COMMENT_LINE = 'comment.line.json';
enum JSONParent { const enum JSONParent {
Object = 0, Object = 0,
Array = 1 Array = 1
} }
class ParentsStack {
constructor(
public readonly parent: ParentsStack | null,
public readonly type: JSONParent
) {}
public static pop(parents: ParentsStack | null): ParentsStack | null {
if (parents) {
return parents.parent;
}
return null;
}
public static push(
parents: ParentsStack | null,
type: JSONParent
): ParentsStack {
return new ParentsStack(parents, type);
}
public static equals(
a: ParentsStack | null,
b: ParentsStack | null
): boolean {
if (!a && !b) {
return true;
}
if (!a || !b) {
return false;
}
while (a && b) {
if (a === b) {
return true;
}
if (a.type !== b.type) {
return false;
}
a = a.parent;
b = b.parent;
}
return true;
}
}
class JSONState implements languages.IState { class JSONState implements languages.IState {
private _state: languages.IState; private _state: languages.IState;
public scanError: json.ScanError; public scanError: json.ScanError;
public lastWasColon: boolean; public lastWasColon: boolean;
public parents: JSONParent[]; public parents: ParentsStack | null;
constructor( constructor(
state: languages.IState, state: languages.IState,
scanError: json.ScanError, scanError: json.ScanError,
lastWasColon: boolean, lastWasColon: boolean,
parents: JSONParent[] parents: ParentsStack | null
) { ) {
this._state = state; this._state = state;
this.scanError = scanError; this.scanError = scanError;
@ -58,29 +102,6 @@ class JSONState implements languages.IState {
this.parents = parents; this.parents = parents;
} }
private static areArraysEqual(first: JSONParent[], second: JSONParent[]) {
if (first === second) {
return true;
}
if (first == null || second === null) {
return false;
}
if (first.length !== second.length) {
return false;
}
let index = -1;
while (++index < first.length) {
if (first[index] !== second[index]) {
return false;
}
}
return true;
}
public clone(): JSONState { public clone(): JSONState {
return new JSONState( return new JSONState(
this._state, this._state,
@ -98,9 +119,9 @@ class JSONState implements languages.IState {
return false; return false;
} }
return ( return (
this.scanError === (<JSONState>other).scanError && this.scanError === other.scanError &&
this.lastWasColon === (<JSONState>other).lastWasColon && this.lastWasColon === other.lastWasColon &&
JSONState.areArraysEqual(this.parents, (<JSONState>other).parents) ParentsStack.equals(this.parents, other.parents)
); );
} }
@ -135,9 +156,9 @@ function tokenize(
break; break;
} }
let scanner = json.createScanner(line), const scanner = json.createScanner(line);
lastWasColon = state.lastWasColon, let lastWasColon = state.lastWasColon;
parents = Array.from(state.parents); let parents = state.parents;
const ret: languages.ILineTokens = { const ret: languages.ILineTokens = {
tokens: <languages.IToken[]>[], tokens: <languages.IToken[]>[],
@ -171,22 +192,22 @@ function tokenize(
// brackets and type // brackets and type
switch (kind) { switch (kind) {
case json.SyntaxKind.OpenBraceToken: case json.SyntaxKind.OpenBraceToken:
parents.push(JSONParent.Object); parents = ParentsStack.push(parents, JSONParent.Object);
type = TOKEN_DELIM_OBJECT; type = TOKEN_DELIM_OBJECT;
lastWasColon = false; lastWasColon = false;
break; break;
case json.SyntaxKind.CloseBraceToken: case json.SyntaxKind.CloseBraceToken:
parents.pop(); parents = ParentsStack.pop(parents);
type = TOKEN_DELIM_OBJECT; type = TOKEN_DELIM_OBJECT;
lastWasColon = false; lastWasColon = false;
break; break;
case json.SyntaxKind.OpenBracketToken: case json.SyntaxKind.OpenBracketToken:
parents.push(JSONParent.Array); parents = ParentsStack.push(parents, JSONParent.Array);
type = TOKEN_DELIM_ARRAY; type = TOKEN_DELIM_ARRAY;
lastWasColon = false; lastWasColon = false;
break; break;
case json.SyntaxKind.CloseBracketToken: case json.SyntaxKind.CloseBracketToken:
parents.pop(); parents = ParentsStack.pop(parents);
type = TOKEN_DELIM_ARRAY; type = TOKEN_DELIM_ARRAY;
lastWasColon = false; lastWasColon = false;
break; break;
@ -208,10 +229,8 @@ function tokenize(
lastWasColon = false; lastWasColon = false;
break; break;
case json.SyntaxKind.StringLiteral: case json.SyntaxKind.StringLiteral:
let currentParent = parents.length const currentParent = parents ? parents.type : JSONParent.Object;
? parents[parents.length - 1] const inArray = currentParent === JSONParent.Array;
: JSONParent.Object;
let inArray = currentParent === JSONParent.Array;
type = type =
lastWasColon || inArray ? TOKEN_VALUE_STRING : TOKEN_PROPERTY_NAME; lastWasColon || inArray ? TOKEN_VALUE_STRING : TOKEN_PROPERTY_NAME;
lastWasColon = false; lastWasColon = false;