SLang이라는 작은 언어를 만들기 시작했습니다

안녕하세요. 이번에는 `SmallLang`이라는 작은 언어를 사부작 만들고 있습니다. 아직은 정말 작습니다. 언어라고 부르기엔 조금 민망할 정도로요… ^^; 그래도 이제 첫 문법이 조금 더 SmallLang 다워졌습니다. ```slang getName: -> Text { "dimohy" } square: Int -> Int { it * it } main { getName -> name 7 -> square -> num "Hello, {name}. square = {num}" -> print } ``` 출력은 이렇습니다. ```text Hello, dimohy. square = 49 ``` 그리고 이 코드는 LLVM IR로 내려간 뒤 Windows x64 네이티브 실행 파일로 링크됩니다. 현재 생성된 exe 크기는: ```text 1,088 bytes ``` 헐… 아직 기능이 작긴 하지만, 실제 실행 파일까지 만들어지는 걸 보면 재미있습니다. ## 문법은 어디로 가고 있나? 처음부터 정하고 싶었던 것은 `let`이나 `var` 없이도 자연스럽게 읽히는 바인딩이었습니다. ```slang name = "dimohy" ``` 여기에 최근에는 값의 흐름을 더 잘 보이게 하는 `->` 문법을 넣었습니다. ```slang getName -> name 7 -> square -> num "Hello, {name}. square = {num}" -> print ``` `getName -> name`은 `getName` 함수를 호출해서 그 결과를 `name`에 바인딩합니다. `7 -> square -> num`은 7이라는 값이 `square` 함수로 흘러가고, 그 결과가 `num`에 바인딩됩니다. 괄호로 쓰면 `num = square(7)` 같은 형태도 가능하지만, SmallLang에서는 일단 "값이 어디로 흘러가는지"가 눈에 보이는 쪽을 선호해보려고 합니다. 함수 타입도 같은 방향성을 갖습니다. ```slang square: Int -> Int { it * it } ``` 지금은 입력이 하나인 함수에서 그 입력을 암묵적으로 `it`으로 받습니다. 그래서 `it * it`이 됩니다. 조금 과감한 선택이긴 한데, 작은 함수에서는 꽤 단순하게 읽히네요. ## 문자열과 숫자 문자열 보간은 가장 작은 형태로 시작했습니다. ```slang "Hello, {name}. square = {num}" ``` 아직은 `{name}`처럼 바인딩 이름을 넣는 정도입니다. 복잡한 표현식을 문자열 안에 바로 넣는 건 조금 더 생각해보려고 합니다. 너무 빨리 다 넣으면 언어가 금방 무거워지더군요. 숫자는 현재 64-bit 정수 리터럴과 `+`, `*`를 지원합니다. `*`가 `+`보다 먼저 묶이고, 둘 다 왼쪽 결합입니다. ## 내부는 어떻게 되어 있나? 컴파일러는 최신 .NET과 C# Preview 기준으로 만들고 있습니다. 처음에는 빠르게 만들다 보니 `Program.cs`에 Lexer까지 들어갔는데… 아아… 이건 바로 정리했습니다. 지금은 역할별로 나누어 두었습니다. - `Cli` - `Lexing` - `Parsing` - `Syntax` - `Semantics` - `CodeGen` - `Tooling` Lexer와 Parser도 손으로 직접 박아두지 않고, 작은 규칙 파일에서 소스 생성기로 만들어지게 했습니다. Lexer 규칙은 이런 식입니다. ```text token Identifier = identifier token String = quoted_string token Number = number token Plus = "+" token Star = "*" token Arrow = "->" token Colon = ":" token Equal = "=" ``` Parser 규칙도 별도 파일에 둡니다. ```text rule FunctionDeclaration = Identifier Colon FunctionSignature LeftBrace NewLine* Expression NewLine* RightBrace rule FunctionSign…