6장: 타입스크립트 컴파일

How does tsc work?

TypeScript Compiler(tsc)란

Abstract SyntaxTree(AST)란

동작 방식

image.png


What is AST?

  1. Abstract Syntax Tree, 추상 구문 트리

  2. 코드의 구문적 요소를 노드로 표현

    1. AST는 코드의 구문적 구조를 트리 구조로 표현, 트리의 각 노드(Node)는 코드의 특정한 구문적 요소를 포함
    2. 예를 들어, 변수 선언, 함수 호출, 조건문, 반복문 등은 각각 구문적 요소
    3. 컴파일러는 코드에서 이러한 구문적 요소들을 분석해 각각을 트리의 노드로 변환
    4. 자세한 구문적 요소 리스트는 링크를 참조 (https://github.com/microsoft/TypeScript/blob/main/src/compiler/types.ts#L39**)**

    예제 코드:

    let x: number = 5;
    

    이 코드는 다음과 같은 구문적 요소로 분해

    이 각 요소가 AST의 노드로 표현

    VariableDeclaration
    ├── Identifier (name = "x")
    ├── TypeAnnotation (type = "number")
    └── Literal (value = 5)
    

    이 트리 구조에서 상위 노드는 하위 노드들을 포함하며, 이러한 노드들의 계층적 관계는 코드의 구문적 구조를 그대로 반영 (6.3 컴파일러의 구조가 이 얘기를 하는 것)

    image.png


  3. 노드의 계층적 관계

    1. AST는 트리 구조를 가지므로 계층적(hierarchical) 관계를 통해 코드의 구조적 요소들을 표현

    2. 이러한 계층 관계 덕분에 컴파일러는 코드의 구문을 쉽게 구분하고 이해 가능

    3. 상위 노드(Parent Node)는 특정 구문을 대표하고, 이 구문에 속한 하위 노드(Child Node)들이 존재

    4. 예제: 함수 호출

      function greet(name: string) {
        console.log("Hello, " + name);
      }
      greet("World");
      

      이 코드를 AST로 표현하면:

      FunctionDeclaration
      ├── Identifier (name = "greet")
      ├── ParameterList
      │   └── Parameter (name = "name", type = "string")
      ├── BlockStatement
      │   └── ExpressionStatement
      │       └── CallExpression
      │           ├── MemberExpression (object = "console", property = "log")
      │           └── BinaryExpression
      │               ├── Literal (value = "Hello, ")
      │               └── Identifier (name = "name")
      CallExpression
      ├── Identifier (name = "greet")
      └── Literal (value = "World")
      

      이 AST를 통해 컴파일러는:

      • FunctionDeclaration이 함수 선언을 의미
      • 함수의 파라미터 리스트와 함수 본문(BlockStatement)이 존재
      • 함수 본문 안에서 console.log가 호출되는 것을 알 수 있음

    계층적 구조 덕분에 컴파일러는 어떤 코드가 어떤 구문에 속해 있는지, 어떤 코드가 어떤 작업을 수행하는지 쉽게 이해할 수 있음


  1. 구문 요소와 노드 타입
    1. AST에서 각 노드는 코드의 구문 요소(Syntax Element)에 해당하며, 특정한 타입을 가짐

    2. 예를 들어, if 문은 IfStatement 타입의 노드로, 함수 선언은 FunctionDeclaration 타입의 노드로 표현

    3. 일반적인 구문 요소와 이에 해당하는 AST 노드 타입의 예시:

      1. 변수 선언: VariableDeclaration
      2. 함수 선언: FunctionDeclaration
      3. 함수 호출: CallExpression
      4. 조건문: IfStatement
      5. 반복문: ForStatement, WhileStatement
      6. 리터럴 값: Literal
      7. 연산자: BinaryExpression (예: +, `` 등의 연산자)
    4. 예제: 조건문

      if (x > 10) {
        console.log("x is greater than 10");
      }
      

      AST는 다음과 같이 구문적 구조를 표현:

      IfStatement
      ├── BinaryExpression (operator = ">")
      │   ├── Identifier (name = "x")
      │   └── Literal (value = 10)
      └── BlockStatement
          └── ExpressionStatement
              └── CallExpression
                  ├── MemberExpression (object = "console", property = "log")
                  └── Literal (value = "x is greater than 10")
      

      IfStatement 노드는 조건문을 표현하고, 그 하위에는 BinaryExpression(이진 연산자) 노드와 BlockStatement(코드 블록) 노드가 위치


  1. 구문적 구조를 통한 의미 이해

    1. 컴파일러가 AST를 통해 코드의 구문적 구조를 이해할 수 있는 이유는 AST가 코드의 구문적 요소를 명확하게 구분하고, 그 관계를 트리 형태로 표현하기 때문

    2. 이는 구문을 해석하고 그 의미를 이해하기 위한 가장 효율적인 방법

    3. 예: 복잡한 함수 호출

      let result = add(2, multiply(3, 4));
      

      이 코드는 다음과 같이 AST로 표현:

      VariableDeclaration
      ├── Identifier (name = "result")
      └── CallExpression (callee = "add")
          ├── Literal (value = 2)
          └── CallExpression (callee = "multiply")
              ├── Literal (value = 3)
              └── Literal (value = 4)