Przeglądaj źródła

Replace array with immutable stack

Alex Dima 4 lat temu
rodzic
commit
bb6231ad91
1 zmienionych plików z 60 dodań i 41 usunięć
  1. 60 41
      src/tokenization.ts

+ 60 - 41
src/tokenization.ts

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