본문 바로가기

Translate Work

타입스크립트 컴파일러의 컴파일 과정

본문 - https://www.huy.rocks/everyday/typescript-how-the-compiler-compiles

 

이 글은, How the Typescript compiler compiles 영상을 참조하여 작성된 글이다. Typescript compile process를 조금 더 깊게 이해하기 위해서, 해당 동영상을 참조 해볼 것을 추천한다.

 


high level 에서, 타입스크립트 컴파일러는 Typescript 코드를 Javascript (*.js) 코드로 컴파일하고, 분석하는데 도움을 줄 수 있는 Tool 이다.

type definition files(*.d.ts) 이나 source maps 파일(*.js.map) 역시도 마찬가지다.

 

 

 


 

만약, 소스 파일에 어떠한 문제가 있다면, 타입 스크립트 컴파일러는 이에 대한 문제를 진단을 해줄 수도 있다. 어디에 어떤 게 잘못 선언되었는지, 그래서 우리가 어떻게 고칠 수 있는지에 대한..

 

타입 스크립트 컴파일러는 내부 프로세스는 다소 복잡하다. 그래도 최대한 요약한 아래 그림을 살펴보자!

 

 


 

타입스크립트 컴파일 프로세스는, 당신이 tsc 명령어를 실행할 때 시작된다.그리고 타입스크립트 컴파일러가 실행되기 위해서는 tsconfig.json 이 필요하다.해당 파일은 기본적으로 2개 영역이 정의 되는데, 하나는 Compiler Options 이고 다른 하나는 Input Files 이다.

{
    "files": [
        "src/*.ts"
    ],
    "compilerOptions": {
        ...
    }
}

 

Compilation contextProgram objectsrc/compiler/program.ts file에 생성이 될 것이다.

생성이 되면, 모든 input files (위 tsconfig.json 내부 files 영역에 정의된 파일들) 과 해당 파일들이 import 하고 있는 모든 파일들을 load 한다.

그리고 각각의 파일들을 AST(Abstract Syntax Tree)로 parse(분석)하기 위해서 Parser(src/compiler/parser.ts)를 호출한다.


내부적으로 ParserScanner 인스턴스(src/compiler/scanner.ts)를 생성하며, Scanner 인스턴스는 소스코드를 스캔 하고

Syntaxkind 토큰들을 생성할 것이다.

 

Syntaxkind 토큰이란 ?

Syntax컴파일러나 interpreter가 쉽고 빠르게 소스코드의 구조를 분석하고 이해할 수 있게 해주는 토큰이다.
예를 들어, 타입스크립트 에서 아마도 키워드 같은 경우 "if" 나 "else" 가 될 수 있을 것이고, operator 같은 경우는 "+", "-" punctuation mark 같은 경우는 "{", "}" 가 될 것이다.
이러한 토큰들은 Typescript의 AST 일부분으로 정의된다.

 

 

Parsing 프로세스는 여기서 멈추지 않고 AST Nodes 와 Symbols 사이의 맵(table?)을 생성하기 위해서,  ASTBinder(src/compiler/binder.ts)로 이어진다. 

 

 

 

Binder 란?

In the TypeScript compile process, the binder is responsible for resolving symbols and types within the program's source code. It is a key component of the compiler's type-checking and analysis phase, which occurs after the program's syntax has been parsed and validated. 
During the binding phase, the TypeScript compiler examines each expression and statement in the program and assigns types to them based on their context and usage within the program. This involves resolving references to variables, functions, classes, and other symbols within the program, and determining their types based on their declarations and usage within the program.
The binder also performs name resolution, which involves identifying the location of symbols within the program and ensuring that there are no conflicts or ambiguities in their usage. 
This can involve resolving namespace or module names, resolving overloaded functions, and checking that variable and function names are unique within their respective scopes.

Overall, the binder plays a crucial role in ensuring that TypeScript programs are well-typed and correctly structured, and helps to catch errors and inconsistencies before the program is executed.

 


 

Symbol 이란? 

In the context of the TypeScript compiler, symbols are programming language constructs that represent declarations of entities such as variables, functions, classes, enums, interfaces, and namespaces.

Symbols are used by the TypeScript compiler to store metadata about the entities declared in the program. 

This metadata includes information about the type and visibility of the entity, as well as its location within the program's source code.

When the TypeScript compiler processes the source code, it creates a symbol for each declaration it encounters. These symbols are then stored in a symbol table, which is used to look up symbols and their associated metadata during subsequent compilation phases, such as type-checking and code generation.

The TypeScript compiler uses symbols to perform various operations during the compilation process, such as resolving types, checking for naming conflicts, and emitting appropriate code. 

 

By using symbols, the compiler can perform these operations more efficiently and accurately than by simply scanning the source code directly.

 

Overall, symbols are a fundamental concept in the TypeScript compiler, and are used extensively throughout the compilation process to represent and manage the program's entities and their associated metadata.

 


 

Binder는 나중에 type checking 단계에서 사용될 Symbols Table을 만든다. Symbol은 개별 노드의 타입정보를 저장하기 위한 추가적인 metadata 이다.

 

이 다음, AST를 Javascript 소스코드 문자열로 변환하기 위해서, Program.emit 호출과 함께  Emit Worker가 생성 될 것이다. 

 

2가지의 Emitters가 있다:

  1.  Javascript Emitter
    1. - src/compiler/emitter.ts
    2. Javascript 코드 와 소스맵들을 emitting(방출) 한다.
  2. Definition Emitter
    1. - src/compiler/definitionEmitter.ts
    2. type definition 파일들을 emitting(방출) 한다.

즉, Emitter는 최종적으로 핵심적인 역할을 담당 한다고 할 수 있다.

Program 단계에서 호출된 ts 파일들을 js 파일들로 변환 해줌으로써, 실제로 브라우저나 다른 자바스크립트 환경에서 실행 될 수 있도록 해주는 단계라 할 수 있다.

 

Emitter가 실행 되면, Type cehcker(src/compiler/checker.ts)를 생성하기 위해 getDiagnostice() 함수를 호출 할 것이다. 그리고,  

Symbols Table에 선언된 각각의 노드들을 순회하며 일치하는 Javascript 코드들을 생성한다.

 

참고로 각각의 노드에서 Symbols Table에 선언된 type data코드 분석을 하고, 문제가 없다면 Javascript 코드가 생성이 된다.