Scanner

Last updated 2 months ago

TypeScript Scannerのソースコードは、完全にscanner.tsにあります。ScannerはソースコードをASTに変換するためにParserによって内部的に制御されます。以下に示すのは、どんな結果が望まれるかです:

SourceCode ~~ scanner ~~> Token Stream ~~ parser ~~> AST

Parserによる使用法

Scannerを何度も作成するコストを避けるために、parser.tsにシングルトンのscannerが作成されています。このスキャナは、initializeState関数を使ってオンデマンドにParserによって準備されます。

ここでは、この概念を説明するParser内の実際のコードのシンプルバージョンを示します:

code/compiler/scanner/runScanner.ts

import * as ts from "ntypescript";
// TypeScript has a singelton scanner
const scanner = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ true);
// That is initialized using a function `initializeState` similar to
function initializeState(text: string) {
scanner.setText(text);
scanner.setOnError((message: ts.DiagnosticMessage, length: number) => {
console.error(message);
});
scanner.setScriptTarget(ts.ScriptTarget.ES5);
scanner.setLanguageVariant(ts.LanguageVariant.Standard);
}
// Sample usage
initializeState(`
var foo = 123;
`.trim());
// Start the scanning
var token = scanner.scan();
while (token != ts.SyntaxKind.EndOfFileToken) {
console.log(ts.formatSyntaxKind(token));
token = scanner.scan();
}

これは以下を出力します:

VarKeyword
Identifier
FirstAssignment
FirstLiteralToken
SemicolonToken

スキャナの状態

scanを呼び出すと、スキャナはローカル状態(スキャン中の位置、現在のトークンの詳細など)を更新します。スキャナには、現在のスキャナの状態を取得するためのユーティリティ機能が用意されています。以下のサンプルでは、スキャナを作成し、それを使用してコード内のトークンとその位置を特定しています。

code/compiler/scanner/runScannerWithPosition.ts

// Sample usage
initializeState(`
var foo = 123;
`.trim());
// Start the scanning
var token = scanner.scan();
while (token != ts.SyntaxKind.EndOfFileToken) {
let currentToken = ts.formatSyntaxKind(token);
let tokenStart = scanner.getStartPos();
token = scanner.scan();
let tokenEnd = scanner.getStartPos();
console.log(currentToken, tokenStart, tokenEnd);
}

これは以下を出力します:

VarKeyword 0 3
Identifier 3 7
FirstAssignment 7 9
FirstLiteralToken 9 13
SemicolonToken 13 14

スタンドアロンScanner

typescript ParserはシングルトンのScannerを持っていますが、createScannerを使ってスタンドアロンScannerを作成し、setText/setTextPosを使って、一興のためにファイル内の異なる位置をスキャンすることができます。