Javascript AST 알아보기

이두팔·2023년 7월 12일
post-thumbnail

어쩐지 오늘은 AST에 대해 알고 싶어졌습니다. 🏄🏻‍♀️

Abstract Syntax Tree

프로그램 코드의 구조를 나타내는 특성 때문에 컴파일러에서 널리 사용되는 데이터 구조입니다.

컴파일러 구문 분석 단계의 결과

노드로 구성되어있고, 각 노드는 코드의 다양한 구성 요소를 나타냅니다.
노드들은 서로 계층적인 관계를 가지고, 트리 구조에서 루트 노드부터 시작하여 자식 노드로 내려가는 형태로 표현하게돼죠.

const a = 'test';

요걸 AST로 변환시키면 아래처럼 됩니다.

{
  "type": "Program",
  "start": 0,
  "end": 17,
  "body": [
    {
      "type": "VariableDeclaration",
      "start": 0,
      "end": 17,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 6,
          "end": 16,
          "id": {
            "type": "Identifier",
            "start": 6,
            "end": 7,
            "name": "a"
          },
          "init": {
            "type": "Literal",
            "start": 10,
            "end": 16,
            "value": "test",
            "raw": "'test'"
          }
        }
      ],
      "kind": "const"
    }
  ],
  "sourceType": "module"
}


활용

Static Analysis

분석
AST는 코드의 구문을 추상화하기 때문에, Javascript 코드를 분석하고 검사하는데 유용해요.
예를 들면 코드에서 사용되는 변수, 함수, 클래스 등의 선언과 참조를 추적하거나
코드의 일관성을 검사하거나, 잠재적인 오류를 감지하는 등 정적 분석 작업을 수행할 수 있습니다.
eslint, tslint 같은 정적 분석 도구에서 AST를 활용해서 코드 검사 기능을 구현할 수 있어요.


타입 체크
Javascript는 동적 언어이기 때문에 런타임에 오류가 발생할 수 있는데요.
정접 타입 체크 도구를 사용해서 코드를 분석하고 타입 오류를 사전에 검출할 수 있습니다.
주로 AST를 사용해서 코드의 타입을 분석하고, 변수, 함수 매개변수, 반환 값 등에 대한 타입 정보를 확인할 수 있어요.

코드를 실행하기 전에 타입 오류를 발견하고,
개발자에게 경고 또는 오류 메시지를 제공해서 프로그램의 안정성과 신뢰성을 높일 수 있답니다.

어디선가 익숙한 설명이지 않나요?!
자주 사용하는 Typescript가 바로 정적 타입 체크 도구에 속합니다.



Transformation

코드 변환
AST를 편집하거나 변환하여 코드를 수정하거나 재구성하는 작업을 수행할 수 있습니다.
요걸로 코드의 자동화, 리팩토링, 언어 확장등을 할 수 있어요.

  1. 코드 재구성
    • AST를 수정해서 코드의 구조를 변경하거나, 불필요한 코드를 제거하거나 코드를 재배치할 수 있습니다.

  2. 코드 생성
    • AST를 기반으로 새로운 코드를 생성하여 기존 코드를 대체할 수 있어요
    • 코드를 최적화하거나 다른 프로그래밍 언어로 변화하는 등의 작업을 수행할 수 있어요

  3. 코드 패턴 변환
    • AST를 사용해서 특정 코드 패턴을 탐지해, 해당 패턴에 맞는 대체 코드를 생성하여 코드를 변환할 수 있어요.
      예) 함수 변환: 콜백 함수를 프로미스로 변환하는 작업
      예) 변수 선언 변환: var 키워드를 let이나 const로 변환하여 변수 스코프를 명확하게 정의
      예) 반복문 변환: for 루프를 Array.map() 또는 Array.forEach() 메서드를 사용하는 형태로 변환

  4. 코드 분석
    • 코드의 의도나 패턴을 파악하는 작업을 수행해서 코드의 품질을 검사하거나, 특정한 보안 취약점을 감지할 수도 있어요


Code Generation

일반적으로 코드 생성 작업을 하려면 AST를 수정해서 새로운 코드를 생성하는 걸로 이루어집니다.
변환 작업을 수행하기 위해 AST 노드를 순회하고, 각 노드의 유형에 따라 적절한 Javascript 코드를 생성해요.
JSX를 Javascript로 변환하는 경우, JSX 요소와 컴포넌트를 Javascript 함수 호출로 변환하는 작업이 수행됩니다.


const element = <h1>내 이름은 씬디</h1>;
const element = React.createElement("h1", null, "내 이름은 씬디");

TSX의 경우 Typescript 컴파일러가 TSX 코드를 AST로 변환한 다음,
AST를 분석하고 수정해서 Javascript 코드로 변환해요.
이를 통해 타입 검사, 코드 변환, 코드 생성이 수행됩니다.

TSX 코드를 Javascript로 변환하는 과정에서 AST를 수정하여 JSX 요소를 Javascript 함수 호출로 변환하거나,
Type Annotation을 제거하고 타입 검사를 수행해요.

Typescript 컴파일러 외에도 Babel, SWC 같은 도구도 TSX를 Javascript로 변환 가능해요.



AST 기반 코드 패턴 변환 구현하기

  1. 소스 코드 파싱
    소스 코드를 파싱해서 AST를 생성합니다.
    여기에서 자바스크립트 파서를 사용할 수 있고, 여러 오픈 소스 라이브러리들이 존재해요

  2. AST 탐색
    생성된 AST를 순회하면서 특정 코드 패턴을 찾는 작업을 수행합니다.
    AST를 재귀적으로 탐색하거나, Visitors 패턴을 사용할 수도 있어요.
    예를 들어 Babel은 Visitors 패턴을 지원하는 @babel/traverse 라이브러리를 제공해요

  3. 코드 변환
    코드 패턴을 찾았을 때, 해당 코드를 원하는 형태로 변환합니다.
    AST의 노드를 수정하거나 새로운 노드를 생성할 수 있어요.
    AST 노드를 수정하는 작업은 노드의 속성을 변경하거나 추가하는 방식으로 이루어집니다.

  4. AST 코드 생성
    변환된 AST를 다시 소스 코드로 생성합니다.
    AST를 재귀적으로 순회하면서 각 노드를 문자열로 변환하는 작업을 수행해요.
    Babel은 AST를 다시 소스 코드로 변환하기 위한 @babel/generator 라이브러리를 제공해요.

라이브러리

Esprima

var ast = esprima.parse("var a = 'test';");

Acorn

var ast = acron.parse('var a;', {
  ranges: true
});                      

직접 사용해보진 않았는데 다음엔 사용해보고 후기도 올리도록 할게요!
잘못된 부분은 알려주세요 !~!

profile
Software Engineer

0개의 댓글