Skip to content

Commit

Permalink
feat: ObjectLiteralExpression
Browse files Browse the repository at this point in the history
Change-Id: I8fdf5340b635531df9b52b6f64f2abb59c0cb625
  • Loading branch information
meixg committed Dec 6, 2018
1 parent 06a3b9e commit bad00c8
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 178 deletions.
10 changes: 4 additions & 6 deletions sample/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
const a = '123';
const b = {};
const c = function(){};

b[a] = 123;
c();
const b = {
a: 123,
b: '456'
};
182 changes: 95 additions & 87 deletions src/emitter.ts

Large diffs are not rendered by default.

283 changes: 206 additions & 77 deletions src/scanner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import {Map, createMapFromTemplate, MapLike} from './core'
import {
Map,
createMapFromTemplate,
MapLike,
identity,
compareValues,
binarySearch
} from './core'
import {positionIsSynthesized} from './utilities';
import * as ts from 'typescript';
import {errors} from './globals';

import {SyntaxKind} from 'typescript';

Expand Down Expand Up @@ -32,86 +41,174 @@ export function computeLineStarts(text: string): number[] {
return result;
}

// export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments = false): number {
// if (positionIsSynthesized(pos)) {
// return pos;
// }
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments = false): number {
if (positionIsSynthesized(pos)) {
return pos;
}

// Keep in sync with couldStartTrivia
while (true) {
const ch = text.charCodeAt(pos);
switch (ch) {
case ts.CharacterCodes.carriageReturn:
if (text.charCodeAt(pos + 1) === ts.CharacterCodes.lineFeed) {
pos++;
}
// falls through
case ts.CharacterCodes.lineFeed:
pos++;
if (stopAfterLineBreak) {
return pos;
}
continue;
case ts.CharacterCodes.tab:
case ts.CharacterCodes.verticalTab:
case ts.CharacterCodes.formFeed:
case ts.CharacterCodes.space:
pos++;
continue;
case ts.CharacterCodes.slash:
if (stopAtComments) {
break;
}
if (text.charCodeAt(pos + 1) === ts.CharacterCodes.slash) {
pos += 2;
while (pos < text.length) {
if (isLineBreak(text.charCodeAt(pos))) {
break;
}
pos++;
}
continue;
}
if (text.charCodeAt(pos + 1) === ts.CharacterCodes.asterisk) {
pos += 2;
while (pos < text.length) {
if (text.charCodeAt(pos) === ts.CharacterCodes.asterisk && text.charCodeAt(pos + 1) === ts.CharacterCodes.slash) {
pos += 2;
break;
}
pos++;
}
continue;
}
break;

case ts.CharacterCodes.lessThan:
case ts.CharacterCodes.bar:
case ts.CharacterCodes.equals:
case ts.CharacterCodes.greaterThan:
if (isConflictMarkerTrivia(text, pos)) {
pos = scanConflictMarkerTrivia(text, pos);
continue;
}
break;

case ts.CharacterCodes.hash:
if (pos === 0 && isShebangTrivia(text, pos)) {
pos = scanShebangTrivia(text, pos);
continue;
}
break;

default:
if (ch > ts.CharacterCodes.maxAsciiCharacter && (isWhiteSpaceLike(ch))) {
pos++;
continue;
}
break;
}
return pos;
}
}

/** Does not include line breaks. For that, see isWhiteSpaceLike. */
export function isWhiteSpaceSingleLine(ch: number): boolean {
// Note: nextLine is in the Zs space, and should be considered to be a whitespace.
// It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript.
return ch === ts.CharacterCodes.space ||
ch === ts.CharacterCodes.tab ||
ch === ts.CharacterCodes.verticalTab ||
ch === ts.CharacterCodes.formFeed ||
ch === ts.CharacterCodes.nonBreakingSpace ||
ch === ts.CharacterCodes.nextLine ||
ch === ts.CharacterCodes.ogham ||
ch >= ts.CharacterCodes.enQuad && ch <= ts.CharacterCodes.zeroWidthSpace ||
ch === ts.CharacterCodes.narrowNoBreakSpace ||
ch === ts.CharacterCodes.mathematicalSpace ||
ch === ts.CharacterCodes.ideographicSpace ||
ch === ts.CharacterCodes.byteOrderMark;
}

export function isWhiteSpaceLike(ch: number): boolean {
return isWhiteSpaceSingleLine(ch) || isLineBreak(ch);
}

const shebangTriviaRegex = /^#!.*/;
function isShebangTrivia(text: string, pos: number) {
// Shebangs check must only be done at the start of the file
return shebangTriviaRegex.test(text);
}

function scanShebangTrivia(text: string, pos: number) {
const shebang = shebangTriviaRegex.exec(text)![0];
pos = pos + shebang.length;
return pos;
}

function scanConflictMarkerTrivia(text: string, pos: number, error?: (diag: ts.DiagnosticMessage, pos?: number, len?: number) => void) {
if (error) {
errors.push({
code: 1,
msg: 'Merge_conflict_marker_encountered' + pos + mergeConflictMarkerLength
});
}

const ch = text.charCodeAt(pos);
const len = text.length;

// // Keep in sync with couldStartTrivia
// while (true) {
// const ch = text.charCodeAt(pos);
// switch (ch) {
// case CharacterCodes.carriageReturn:
// if (text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) {
// pos++;
// }
// // falls through
// case CharacterCodes.lineFeed:
// pos++;
// if (stopAfterLineBreak) {
// return pos;
// }
// continue;
// case CharacterCodes.tab:
// case CharacterCodes.verticalTab:
// case CharacterCodes.formFeed:
// case CharacterCodes.space:
// pos++;
// continue;
// case CharacterCodes.slash:
// if (stopAtComments) {
// break;
// }
// if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
// pos += 2;
// while (pos < text.length) {
// if (isLineBreak(text.charCodeAt(pos))) {
// break;
// }
// pos++;
// }
// continue;
// }
// if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
// pos += 2;
// while (pos < text.length) {
// if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) {
// pos += 2;
// break;
// }
// pos++;
// }
// continue;
// }
// break;
if (ch === ts.CharacterCodes.lessThan || ch === ts.CharacterCodes.greaterThan) {
while (pos < len && !isLineBreak(text.charCodeAt(pos))) {
pos++;
}
}
else {
// Consume everything from the start of a ||||||| or ======= marker to the start
// of the next ======= or >>>>>>> marker.
while (pos < len) {
const currentChar = text.charCodeAt(pos);
if ((currentChar === ts.CharacterCodes.equals || currentChar === ts.CharacterCodes.greaterThan) && currentChar !== ch && isConflictMarkerTrivia(text, pos)) {
break;
}

pos++;
}
}

// case CharacterCodes.lessThan:
// case CharacterCodes.bar:
// case CharacterCodes.equals:
// case CharacterCodes.greaterThan:
// if (isConflictMarkerTrivia(text, pos)) {
// pos = scanConflictMarkerTrivia(text, pos);
// continue;
// }
// break;
return pos;
}

// case CharacterCodes.hash:
// if (pos === 0 && isShebangTrivia(text, pos)) {
// pos = scanShebangTrivia(text, pos);
// continue;
// }
// break;
const mergeConflictMarkerLength = "<<<<<<<".length;
function isConflictMarkerTrivia(text: string, pos: number) {

// default:
// if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpaceLike(ch))) {
// pos++;
// continue;
// }
// break;
// }
// return pos;
// }
// }
// Conflict markers must be at the start of a line.
if (pos === 0 || isLineBreak(text.charCodeAt(pos - 1))) {
const ch = text.charCodeAt(pos);

if ((pos + mergeConflictMarkerLength) < text.length) {
for (let i = 0; i < mergeConflictMarkerLength; i++) {
if (text.charCodeAt(pos + i) !== ch) {
return false;
}
}

return ch === ts.CharacterCodes.equals ||
text.charCodeAt(pos + mergeConflictMarkerLength) === ts.CharacterCodes.space;
}
}

return false;
}

export function isLineBreak(ch: number): boolean {
// ES5 7.3:
Expand Down Expand Up @@ -278,4 +375,36 @@ const tokenStrings = makeReverseMap(textToToken);

export function tokenToString(t: SyntaxKind): string | undefined {
return tokenStrings[t];
}

export function computeLineAndCharacterOfPosition(lineStarts: ReadonlyArray<number>, position: number): ts.LineAndCharacter {
let lineNumber = binarySearch(lineStarts, position, identity, compareValues);
if (lineNumber < 0) {
// If the actual position was not found,
// the binary search returns the 2's-complement of the next line start
// e.g. if the line starts at [5, 10, 23, 80] and the position requested was 20
// then the search will return -2.
//
// We want the index of the previous line start, so we subtract 1.
// Review 2's-complement if this is confusing.
lineNumber = ~lineNumber - 1;
if (lineNumber === -1) {
errors.push({
code: 1,
msg: "position cannot precede the beginning of the file"
});
}
}
return {
line: lineNumber,
character: position - lineStarts[lineNumber]
};
}

export function getLineAndCharacterOfPosition(sourceFile: ts.SourceFileLike, position: number): ts.LineAndCharacter {
return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position);
}

export function getLineStarts(sourceFile: ts.SourceFileLike): ReadonlyArray<number> {
return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text));
}
49 changes: 44 additions & 5 deletions src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*/

import {
computeLineStarts
computeLineStarts,
skipTrivia,
getLineAndCharacterOfPosition
} from './scanner';
import {
last,
Expand Down Expand Up @@ -233,10 +235,19 @@ export function unescapeLeadingUnderscores(identifier: ts.__String): string {
// return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos);
// }

// export function positionsAreOnSameLine(pos1: number, pos2: number, sourceFile: SourceFile) {
// return pos1 === pos2 ||
// getLineOfLocalPosition(sourceFile, pos1) === getLineOfLocalPosition(sourceFile, pos2);
// }
export function positionsAreOnSameLine(pos1: number, pos2: number, sourceFile: ts.SourceFile) {
return pos1 === pos2 ||
getLineOfLocalPosition(sourceFile, pos1) === getLineOfLocalPosition(sourceFile, pos2);
}
export function rangeEndIsOnSameLineAsRangeStart(range1: ts.TextRange, range2: ts.TextRange, sourceFile: ts.SourceFile) {
return positionsAreOnSameLine(range1.end, getStartPositionOfRange(range2, sourceFile), sourceFile);
}
export function getLineOfLocalPosition(currentSourceFile: ts.SourceFile, pos: number) {
return getLineAndCharacterOfPosition(currentSourceFile, pos).line;
}
export function getStartPositionOfRange(range: ts.TextRange, sourceFile: ts.SourceFile) {
return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos);
}

export function isGeneratedIdentifier(node: ts.Node) {
return isIdentifier(node) && ((<ts.Identifier>node).autoGenerateFlags! & ts.GeneratedIdentifierFlags.KindMask) > ts.GeneratedIdentifierFlags.None;
Expand All @@ -246,6 +257,34 @@ export function isIdentifier(node: ts.Node) {
return node.kind === ts.SyntaxKind.Identifier;
}

// Binding patterns

/* @internal */
export function isBindingPattern(node: Node | undefined): node is ts.BindingPattern {
if (node) {
const kind = node.kind;
return kind === ts.SyntaxKind.ArrayBindingPattern
|| kind === ts.SyntaxKind.ObjectBindingPattern;
}

return false;
}

/* @internal */
export function isAssignmentPattern(node: Node): node is ts.AssignmentPattern {
const kind = node.kind;
return kind === ts.SyntaxKind.ArrayLiteralExpression
|| kind === ts.SyntaxKind.ObjectLiteralExpression;
}


/* @internal */
export function isArrayBindingElement(node: Node): node is ts.ArrayBindingElement {
const kind = node.kind;
return kind === ts.SyntaxKind.BindingElement
|| kind === ts.SyntaxKind.OmittedExpression;
}

// export function getSourceTextOfNodeFromSourceFile(sourceFile: ts.SourceFile, node: Node, includeTrivia = false): string {
// return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia);
// }
Expand Down
Loading

0 comments on commit bad00c8

Please sign in to comment.