AST

8/19/2025

์ฐธ๊ณ  :
์œ„ํ‚คํ”ผ๋””์•„
https://yceffort.kr/2021/05/ast-for-javascript

Abstract Syntax Tree, ํ•œ๊ตญ์–ด๋กœ '์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ'๋ผ๊ณ  ํ•œ๋‹ค.
ํ”„๋กœ๊ทธ๋žจ ์ฝ”๋“œ๋ฅผ ํŠธ๋ฆฌ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค์–ด ๊ตฌ์กฐํ™”ํ•œ ๊ฒฐ๊ณผ๋ฌผ์ด๋‹ค.

const x = 10;

//์œ„์˜ ๋ณ€์ˆ˜ ์„ ์–ธ & ์ดˆ๊ธฐํ™”๋ฌธ์€ AST๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€ํ•œ๋‹ค.

{
	"type": "VariableDeclaration", // "์ด๊ฑด ๋ณ€์ˆ˜ ์„ ์–ธ๋ฌธ์ด์•ผ"
	"kind": "const",              // "const ์ข…๋ฅ˜์˜ ๋ณ€์ˆ˜์•ผ"
	"declarations": [             // "์„ ์–ธ๋œ ๋ณ€์ˆ˜ ๋ชฉ๋ก์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„"
		{
		"id": { "name": "x" },     // "๋ณ€์ˆ˜ ์ด๋ฆ„์€ 'x'์ด๊ณ "
		"init": { "value": 10 }    // "์ดˆ๊ธฐ๊ฐ’์€ 10์ด์•ผ"
		}
	]
}
function square(n) {
  return n * n
}

//์œ„์˜ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€ํ™˜๋œ๋‹ค.
//babel ์ปดํŒŒ์ผ๋Ÿฌ

{
  "type": "Program",
  "start": 0,
  "end": 36,
  "loc": {
    "start": {
      "line": 1,
      "column": 0
    },
    "end": {
      "line": 3,
      "column": 1
    }
  },
  "range": [0, 36],
  "errors": [],
  "comments": [],
  "sourceType": "module",
  "body": [
    {
      "type": "FunctionDeclaration",
      "start": 0,
      "end": 36,
      "loc": {
        "start": {
          "line": 1,
          "column": 0
        },
        "end": {
          "line": 3,
          "column": 1
        }
      },
      "range": [0, 36],
      "id": {
        "type": "Identifier",
        "start": 9,
        "end": 15,
        "loc": {
          "start": {
            "line": 1,
            "column": 9
          },
          "end": {
            "line": 1,
            "column": 15
          },
          "identifierName": "square"
        },
        "range": [9, 15],
        "name": "square",
        "_babelType": "Identifier"
      },
      "generator": false,
      "async": false,
      "expression": false,
      "params": [
        {
          "type": "Identifier",
          "start": 16,
          "end": 17,
          "loc": {
            "start": {
              "line": 1,
              "column": 16
            },
            "end": {
              "line": 1,
              "column": 17
            },
            "identifierName": "n"
          },
          "range": [16, 17],
          "name": "n",
          "_babelType": "Identifier"
        }
      ],
      "body": {
        "type": "BlockStatement",
        "start": 18,
        "end": 36,
        "loc": {
          "start": {
            "line": 1,
            "column": 18
          },
          "end": {
            "line": 3,
            "column": 1
          }
        },
        "range": [18, 36],
        "body": [
          {
            "type": "ReturnStatement",
            "start": 22,
            "end": 34,
            "loc": {
              "start": {
                "line": 2,
                "column": 2
              },
              "end": {
                "line": 2,
                "column": 14
              }
            },
            "range": [22, 34],
            "argument": {
              "type": "BinaryExpression",
              "start": 29,
              "end": 34,
              "loc": {
                "start": {
                  "line": 2,
                  "column": 9
                },
                "end": {
                  "line": 2,
                  "column": 14
                }
              },
              "range": [29, 34],
              "left": {
                "type": "Identifier",
                "start": 29,
                "end": 30,
                "loc": {
                  "start": {
                    "line": 2,
                    "column": 9
                  },
                  "end": {
                    "line": 2,
                    "column": 10
                  },
                  "identifierName": "n"
                },
                "range": [29, 30],
                "name": "n",
                "_babelType": "Identifier"
              },
              "operator": "*",
              "right": {
                "type": "Identifier",
                "start": 33,
                "end": 34,
                "loc": {
                  "start": {
                    "line": 2,
                    "column": 13
                  },
                  "end": {
                    "line": 2,
                    "column": 14
                  },
                  "identifierName": "n"
                },
                "range": [33, 34],
                "name": "n",
                "_babelType": "Identifier"
              },
              "_babelType": "BinaryExpression"
            },
            "_babelType": "ReturnStatement"
          }
        ],
        "_babelType": "BlockStatement"
      },
      "_babelType": "FunctionDeclaration"
    }
  ]
}

์ƒ์„ฑ ๊ณผ์ •

  1. ํ† ํฐํ™” Tokenization
    • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ๋ฌธ๋ฒ• ๊ทœ์น™์— ๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ํ† ํฐ ๋‹จ์œ„๋กœ ๋ถ„ํ•ด
    • ์˜ˆ:ย const x = 10;
      • const: ๋ณ€์ˆ˜ ์„ ์–ธ ํ‚ค์›Œ๋“œ
      • x: ๋ณ€์ˆ˜๋ช…
      • =: ํ• ๋‹น ์—ฐ์‚ฐ์ž
      • 10: ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’
  2. ํŒŒ์‹ฑ Parsing
    • ํ† ํฐ๋“ค์„ ๋ฌธ๋ฒ• ๊ทœ์น™์— ๋”ฐ๋ผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์กฐํ•ฉ
    • ๊ฐ ๋…ธ๋“œ๋Š” ์ฝ”๋“œ์˜ ์˜๋ฏธ์  ์š”์†Œ๋ฅผ ๋‚˜ํƒ€๋ƒ„

์ฝ”๋“œ๋ฅผ ์ด๋ ‡๊ฒŒ ์ชผ๊ฐœ์„œ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค์–ด์•ผ ์ปดํ“จํ„ฐ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.
๊ทธ๋ž˜์„œ IDE๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ IDE๊ฐ€ ๋ฏธ๋ฆฌ ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๋ฅผ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š”๊ฒƒ.
๊ทธ๋ฆฌ๊ณ  ๊ถ๊ทน์ ์œผ๋กœ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ณ ๊ธ‰์–ด ์ฝ”๋“œ๋ฅผ ๊ธฐ๊ณ„์–ด๋กœ ๋ฒˆ์—ญํ•˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์ด ์ปดํ“จํ„ฐ์—์„œ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

unifiedjs ์—์„œ

unified ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” HTML๊ณผ Markdown ์ฝ”๋“œ๋ฅผ AST๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , AST๋ฅผ ๋‹ค์‹œ HTML์ด๋‚˜ Markdown ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ๋‹ค์–‘ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” 500๊ฐœ๊ฐ€ ๋„˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์˜ ์ƒํƒœ๊ณ„๋‹ค.
remark๋Š” mdํŒŒ์ผ์„ AST๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ , rehype๋Š” htmlํŒŒ์ผ์„ AST๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
๋‘˜ ์‚ฌ์ด์— ์žˆ๋Š” ๊ณตํ†ต๋œ AST์— ๋Œ€ํ•œ ๊ทœ๊ฒฉ์˜ ํ†ต์ผ(ํ˜ธํ™˜)์€ ๋ชจ๋‘ unified๋ผ๋Š” ์ „์ฒด์ ์ธ ๊ณผ์ •์•ˆ์—์„œ ์ด๋ฃจ์–ด์ง€๋ฉด์„œ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค.

const processedContent = await remark()
	.use(breaks)
	.use(remarkMath)
	.use(remarkRehype)
	.use(rehypeKatex)
	.use(rehypeStringify)
	.process(matterResult.content);

const contentHTML = processedContent.toString();

์ด๋ ‡๊ฒŒ use()๋ฅผ ํ†ตํ•ด ๊ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์˜ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์”ฉ ์ถ”๊ฐ€ํ•ด ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.