Scanner
TypeScript/scanner.ts at 3cd9f3d2d4afc1c817ea53b3e40d9598197e9aaa · Microsoft/TypeScript · GitHub
export interface Scanner { getStartPos(): number; getToken(): SyntaxKind; getTextPos(): number; getTokenPos(): number; getTokenText(): string; getTokenValue(): string; hasExtendedUnicodeEscape(): boolean; hasPrecedingLineBreak(): boolean; isIdentifier(): boolean; isReservedWord(): boolean; isUnterminated(): boolean; /* @internal */ getNumericLiteralFlags(): NumericLiteralFlags; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; reScanTemplateToken(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxToken(): SyntaxKind; scanJsxToken(): SyntaxKind; scanJSDocToken(): SyntaxKind; scan(): SyntaxKind; getText(): string; // Sets the text for the scanner to scan. An optional subrange starting point and length // can be provided to have the scanner only scan a portion of the text. setText(text: string, start?: number, length?: number): void; setOnError(onError: ErrorCallback): void; setScriptTarget(scriptTarget: ScriptTarget): void; setLanguageVariant(variant: LanguageVariant): void; setTextPos(textPos: number): void; // Invokes the provided callback then unconditionally restores the scanner to the state it // was in immediately prior to invoking the callback. The result of invoking the callback // is returned from this function. lookAhead<T>(callback: () => T): T; // Invokes the callback with the scanner set to scan the specified range. When the callback // returns, the scanner is restored to the state it was in before scanRange was called. scanRange<T>(start: number, length: number, callback: () => T): T; // Invokes the provided callback. If the callback returns something falsy, then it restores // the scanner to the state it was in immediately prior to invoking the callback. If the // callback returns something truthy, then the scanner state is not rolled back. The result // of invoking the callback is returned from this function. tryScan<T>(callback: () => T): T; }
Interfaceとしてはこんな感じ。与えられた文字列に対して scan()
で1文字ずつ舐めていって token( SyntaxKind
) を取得する。
TypeScript/types.ts at 3cd9f3d2d4afc1c817ea53b3e40d9598197e9aaa · Microsoft/TypeScript · GitHub
tokenが識別子(keyword)かどうかは token > SyntaxKind.Identifer
で判定できるようになっている。最近入ったJSDocの解釈に対応するつため JSDoc*Type
みたいな SyntaxKind
もある。以前だったら単なるコメントなので *CommentTrivia
扱いされていたはず。はず。
scan()
自体は普通に pos
を進めていきながら token
を判定していく感じ。
TypeScript/scanner.ts at 3cd9f3d2d4afc1c817ea53b3e40d9598197e9aaa · Microsoft/TypeScript · GitHub
TypeScriptはあんまり独自のキーワードいれない(実JSに影響及ぼすものに関しては)方針だと思われるけどその中でも enum
だけは存在しているのは多分
switch (ch) { case CharacterCodes.lineFeed:
みたいなのを書きやすくするためなんじゃないかなぁと思ってる。セルフホスティングだからね。
jsxだったりテンプレートリテラルだったりする場合は特別対応してるんだけど、正直なにやってるかよくわからない。
import * as ts from 'typescript'; let text = `let a = 'm';`; let scanner = ts.createScanner(ts.ScriptTarget.Latest, false,ts.LanguageVariant.Standard, text); console.log(scanner.scan()); console.log(scanner.getTokenValue());
みたいなの書いていけば理解できそうだけどparser読んだほうが良さそうなので今は置いとく。 reScan
系とか使ってる側見たいとイメージ沸かない。
ちなみに ConflictMarkerTrivia
みたいのもあって親切。