| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { InvalidBracketAstNode, ListAstNode, PairAstNode } from './ast.js';
- import { BeforeEditPositionMapper } from './beforeEditPositionMapper.js';
- import { SmallImmutableSet } from './smallImmutableSet.js';
- import { lengthIsZero, lengthLessThan } from './length.js';
- import { concat23Trees, concat23TreesOfSameHeight } from './concat23Trees.js';
- import { NodeReader } from './nodeReader.js';
- /**
- * Non incrementally built ASTs are immutable.
- */
- export function parseDocument(tokenizer, edits, oldNode, createImmutableLists) {
- const parser = new Parser(tokenizer, edits, oldNode, createImmutableLists);
- return parser.parseDocument();
- }
- /**
- * Non incrementally built ASTs are immutable.
- */
- class Parser {
- constructor(tokenizer, edits, oldNode, createImmutableLists) {
- this.tokenizer = tokenizer;
- this.createImmutableLists = createImmutableLists;
- this._itemsConstructed = 0;
- this._itemsFromCache = 0;
- if (oldNode && createImmutableLists) {
- throw new Error('Not supported');
- }
- this.oldNodeReader = oldNode ? new NodeReader(oldNode) : undefined;
- this.positionMapper = new BeforeEditPositionMapper(edits, tokenizer.length);
- }
- parseDocument() {
- this._itemsConstructed = 0;
- this._itemsFromCache = 0;
- let result = this.parseList(SmallImmutableSet.getEmpty());
- if (!result) {
- result = ListAstNode.getEmpty();
- }
- return result;
- }
- parseList(openedBracketIds) {
- const items = new Array();
- while (true) {
- const token = this.tokenizer.peek();
- if (!token ||
- (token.kind === 2 /* TokenKind.ClosingBracket */ &&
- token.bracketIds.intersects(openedBracketIds))) {
- break;
- }
- const child = this.parseChild(openedBracketIds);
- if (child.kind === 4 /* AstNodeKind.List */ && child.childrenLength === 0) {
- continue;
- }
- items.push(child);
- }
- // When there is no oldNodeReader, all items are created from scratch and must have the same height.
- const result = this.oldNodeReader ? concat23Trees(items) : concat23TreesOfSameHeight(items, this.createImmutableLists);
- return result;
- }
- parseChild(openedBracketIds) {
- if (this.oldNodeReader) {
- const maxCacheableLength = this.positionMapper.getDistanceToNextChange(this.tokenizer.offset);
- if (!lengthIsZero(maxCacheableLength)) {
- const cachedNode = this.oldNodeReader.readLongestNodeAt(this.positionMapper.getOffsetBeforeChange(this.tokenizer.offset), curNode => {
- if (!lengthLessThan(curNode.length, maxCacheableLength)) {
- // Either the node contains edited text or touches edited text.
- // In the latter case, brackets might have been extended (`end` -> `ending`), so even touching nodes cannot be reused.
- return false;
- }
- const canBeReused = curNode.canBeReused(openedBracketIds);
- return canBeReused;
- });
- if (cachedNode) {
- this._itemsFromCache++;
- this.tokenizer.skip(cachedNode.length);
- return cachedNode;
- }
- }
- }
- this._itemsConstructed++;
- const token = this.tokenizer.read();
- switch (token.kind) {
- case 2 /* TokenKind.ClosingBracket */:
- return new InvalidBracketAstNode(token.bracketIds, token.length);
- case 0 /* TokenKind.Text */:
- return token.astNode;
- case 1 /* TokenKind.OpeningBracket */: {
- const set = openedBracketIds.merge(token.bracketIds);
- const child = this.parseList(set);
- const nextToken = this.tokenizer.peek();
- if (nextToken &&
- nextToken.kind === 2 /* TokenKind.ClosingBracket */ &&
- (nextToken.bracketId === token.bracketId || nextToken.bracketIds.intersects(token.bracketIds))) {
- this.tokenizer.read();
- return PairAstNode.create(token.astNode, child, nextToken.astNode);
- }
- else {
- return PairAstNode.create(token.astNode, child, null);
- }
- }
- default:
- throw new Error('unexpected');
- }
- }
- }
|