Han (한) Programming Language
Han is a statically-typed, compiled programming language where every keyword is written in Korean (Hangul). It compiles to native binaries through LLVM IR and includes a tree-walking interpreter for instant execution.
Quick Example
함수 인사(이름: 문자열) {
출력("${이름}님 안녕하세요")
}
인사("세계")
Output: 세계님 안녕하세요
Key Features
- Korean keywords —
함수,만약,이면,반복,변수 - Korean word order —
만약 조건 이면 { },조건 동안 { } - String interpolation —
"${expr}"auto-desugars to형식() - Korean logical operators —
그리고,또는 - Dual execution — interpreter (
hgl interpret) and compiler (hgl build) - Tooling —
hgl check,hgl init, VS Code extension, and LSP support - Learning path —
examples/교육_*.hglincludes 10 SOV-first educational programs - Arrays, structs, enums, tuples, closures, pattern matching
- Error handling —
시도/처리with Elm-style source-context errors - File I/O, format strings, module imports
How It Works
Source (.hgl) → Lexer → Parser → AST → Interpreter (direct execution)
→ CodeGen → LLVM IR → clang → Binary
Installation
Prerequisites
- Rust 1.70+
- clang (for
hgl build/hgl run) — optional for interpreter-only use
macOS
xcode-select --install
Linux
sudo apt install clang
Install Han
git clone https://github.com/xodn348/han.git
cd han
cargo install --path .
hgl is now available globally.
Verify Installation
hgl --help
Hello World
Create a file called hello.hgl:
출력("안녕하세요, 세계!")
Run it:
hgl interpret hello.hgl
Output:
안녕하세요, 세계!
With a Function
함수 main() {
출력("Hello from Han!")
}
main()
Compile to Binary
hgl build hello.hgl # creates ./hello binary
./hello # runs natively
REPL
Start the interactive REPL:
hgl repl
Han (한) REPL v0.2.0
종료: Ctrl+D 또는 '나가기' 입력
한> 변수 x = 42
한> 출력(x * 2)
84
한> 나가기
안녕히 가세요!
The REPL maintains state between lines — variables and functions persist across inputs.
Learn Korean Through Coding
Every keyword in Han is a real Korean word. If you're learning Korean, writing Han code is a way to practice reading Hangul in context.
Keyword Pronunciation Guide
| Code | Pronunciation | Meaning | What it does |
|---|---|---|---|
함수 | ham-su | function (math term) | defines a function |
만약 | man-yak | if/suppose | starts a conditional |
이면 | i-myeon | then/if-then | marks the Korean-default conditional ending |
반환 | ban-hwan | return/give back | returns a value |
변수 | byeon-su | variable (math term) | declares a mutable variable |
상수 | sang-su | constant | declares an immutable constant |
반복 | ban-bok | repetition | for loop |
동안 | dong-an | during/while | while loop |
출력 | chul-ryeok | output | prints to console |
입력 | ip-ryeok | input | reads from console |
참 | cham | true/truth | boolean true |
거짓 | geo-jit | false/lie | boolean false |
없음 | eop-seum | nothing/none | null value |
구조 | gu-jo | structure | defines a struct |
열거 | yeol-geo | enumeration | defines an enum |
아니면 | a-ni-myeon | otherwise | else branch |
멈춰 | meom-chwo | stop | break |
계속 | gye-sok | continue | continue |
시도 | si-do | attempt | try block |
처리 | cheo-ri | handling/process | catch block |
맞춤 | mat-chwo | match/fit | pattern matching |
포함 | po-ham | include/contain | import module |
그리고 | geu-ri-go | and (conjunction) | logical AND |
또는 | tto-neun | or (alternative) | logical OR |
안에서 | an-e-seo | inside/within | for-in iteration |
Method Names
Array and string methods are also real Korean verbs:
| Method | Pronunciation | Meaning |
|---|---|---|
추가 | chu-ga | add/append |
삭제 | sak-je | delete/remove |
포함 | po-ham | contain/include |
정렬 | jeong-ryeol | sort/arrange |
역순 | yeok-sun | reverse order |
분리 | bun-ri | separate/split |
바꾸기 | ba-kku-gi | change/replace |
합치기 | hap-chi-gi | combine/join |
길이 | gi-ri | length |
Type Names
| Type | Pronunciation | Meaning |
|---|---|---|
정수 | jeong-su | integer (whole number) |
실수 | sil-su | real number (float) |
문자열 | mun-ja-yeol | character string |
불 | bul | boolean (fire/light) |
Example: Reading Han Code as Korean
함수 인사(이름: 문자열) {
출력("${이름}님 안녕하세요")
}
Reading this as Korean:
함수(function)인사(greeting) — "define a greeting function"이름(name):문자열(string) — "parameter: name of type string"출력(output) — "print"${이름}— insert the이름variable into the string안녕하세요(annyeonghaseyo) — "hello" (formal)
Every line is readable Korean.
Variables & Constants
Mutable Variables
변수 이름 = 42
변수 메시지 = "안녕하세요"
이름 = 100 // reassignment allowed
Constants
상수 파이 = 3.14
// 파이 = 3.0 → runtime error: cannot reassign constant
Type Annotations
변수 나이: 정수 = 25
변수 키: 실수 = 175.5
변수 이름: 문자열 = "홍길동"
변수 활성: 불 = 참
Null Values
변수 값 = 없음
출력(값) // 없음
Data Types
Primitive Types
| Type | Han | Description | Examples |
|---|---|---|---|
| Integer | 정수 | 64-bit signed integer | 42, -10, 0 |
| Float | 실수 | 64-bit floating point | 3.14, -0.5 |
| String | 문자열 | UTF-8 string | "안녕하세요" |
| Boolean | 불 | true/false | 참, 거짓 |
| Void | 없음 | null/void | 없음 |
Type Coercion
Int and Float mix automatically:
출력(1 + 1.5) // 2.5 (Float)
출력(3 * 2.0) // 6.0 (Float)
출력(10 - 0.5) // 9.5 (Float)
Compound Types
- Arrays:
[1, 2, 3]— type[정수] - Tuples:
(1, "hello", 참)— type(정수, 문자열, 불) - Structs:
구조 사람 { 이름: 문자열 } - Enums:
열거 방향 { 위, 아래 }
Functions
Declaration
함수 더하기(가: 정수, 나: 정수) -> 정수 {
반환 가 + 나
}
Calling
변수 결과 = 더하기(3, 4)
출력(결과) // 7
No Return Type (void)
함수 인사(이름: 문자열) {
출력(형식("안녕, {0}!", 이름))
}
Recursion
함수 피보나치(n: 정수) -> 정수 {
만약 n <= 1 이면 {
반환 n
}
반환 피보나치(n - 1) + 피보나치(n - 2)
}
Generics (syntax only)
함수 첫번째<T>(arr: [T]) -> T {
반환 arr[0]
}
Type parameters are parsed but erased at runtime.
Function Type Parameter
함수 적용(f: 함수, x: 정수) -> 정수 {
반환 f(x)
}
Control Flow
If / Else-If / Else
The Korean-default conditional form uses 이면. The older minimal form is still supported, but the docs use the 이면 style:
만약 점수 >= 90 이면 {
출력("A")
} 아니면 점수 >= 80 이면 {
출력("B")
} 아니면 {
출력("C")
}
Logical Operators
만약 로그인됨 그리고 관리자 이면 {
출력("관리자 메뉴")
}
만약 오프라인 또는 점검중 이면 {
출력("잠시 후 다시 시도하세요")
}
For Loop
반복 변수 i = 0; i < 10; i += 1 {
출력(i)
}
For-In Loop
Iterate over arrays:
반복 과일 안에서 ["사과", "배", "포도"] {
출력(과일)
}
Iterate over strings:
반복 글자 안에서 "한글" {
출력(글자) // 한, 글
}
Iterate over ranges:
반복 i 안에서 0..5 {
출력(i) // 0, 1, 2, 3, 4
}
While Loop
SOV:
변수 n = 0
n < 5 동안 {
출력(n)
n += 1
}
SVO (traditional alternative):
변수 n = 0
동안 n < 5 {
출력(n)
n += 1
}
Break and Continue
반복 i 안에서 0..100 {
만약 i == 50 이면 { 멈춰 }
만약 i % 2 == 0 이면 { 계속 }
출력(i)
}
Range Operator
변수 범위 = 0..10 // creates [0, 1, 2, ..., 9]
변수 길이 = 범위.길이() // 10
Arrays
Creating Arrays
변수 숫자 = [1, 2, 3, 4, 5]
변수 빈배열 = []
Indexing
출력(숫자[0]) // 1
출력(숫자[-1]) // 5 (negative indexing)
숫자[0] = 99 // mutation
Methods
| Method | Description | Example |
|---|---|---|
.추가(값) | Append element | arr.추가(6) |
.삭제(인덱스) | Remove at index | arr.삭제(0) |
.길이() | Length | arr.길이() → 5 |
.포함(값) | Contains | arr.포함(3) → 참 |
.역순() | Reverse (new array) | arr.역순() |
.정렬() | Sort (new array) | arr.정렬() |
.합치기(구분자) | Join to string | arr.합치기(", ") |
Iteration
반복 항목 안에서 [1, 2, 3] {
출력(항목)
}
Structs
Definition
구조 사람 {
이름: 문자열,
나이: 정수
}
Instantiation
변수 홍길동 = 사람 { 이름: "홍길동", 나이: 30 }
Field Access
출력(홍길동.이름) // 홍길동
출력(홍길동.나이) // 30
Field Mutation
홍길동.나이 = 31
Nested Structs
구조 주소 { 도시: 문자열 }
구조 직원 { 이름: 문자열, 주소: 주소 }
변수 p = 직원 { 이름: "김철수", 주소: 주소 { 도시: "서울" } }
출력(p.주소.도시) // 서울
p.주소.도시 = "부산" // nested mutation
Impl Blocks (Methods)
구현 사람 {
함수 소개(자신: 사람) {
출력(형식("{0}, {1}세", 자신.이름, 자신.나이))
}
}
홍길동.소개() // 홍길동, 30세
자신 is the self parameter — refers to the struct instance.
Enums
Definition
열거 방향 {
위,
아래,
왼쪽,
오른쪽
}
Access
Variants are accessed with :::
출력(방향::위) // 0
출력(방향::아래) // 1
출력(방향::오른쪽) // 3
Variants are integer values starting from 0.
Pattern Matching with Enums
맞춤 방향::아래 {
0 => 출력("위")
1 => 출력("아래")
_ => 출력("기타")
}
Tuples
Creating Tuples
변수 좌표 = (10, 20)
변수 사람 = ("홍길동", 30, 참)
Access by Index
출력(좌표.0) // 10
출력(좌표.1) // 20
출력(사람.0) // 홍길동
As Return Type
함수 최소최대(arr: [정수]) -> (정수, 정수) {
변수 최소 = arr[0]
변수 최대 = arr[0]
반복 v 안에서 arr {
만약 v < 최소 이면 { 최소 = v }
만약 v > 최대 이면 { 최대 = v }
}
반환 (최소, 최대)
}
변수 결과 = 최소최대([5, 1, 9, 3, 7])
출력(형식("최소: {0}, 최대: {1}", 결과.0, 결과.1))
Closures
Anonymous Functions
변수 두배 = 함수(x: 정수) { 반환 x * 2 }
출력(두배(5)) // 10
Environment Capture
Closures capture variables from their enclosing scope:
변수 배수 = 3
변수 곱하기 = 함수(x: 정수) { 반환 x * 배수 }
출력(곱하기(5)) // 15
Passing as Arguments
함수 적용(f: 함수, x: 정수) -> 정수 {
반환 f(x)
}
변수 제곱 = 함수(x: 정수) { 반환 x * x }
출력(적용(제곱, 4)) // 16
Pattern Matching
Basic Match
맞춤 값 {
1 => 출력("하나")
2 => 출력("둘")
_ => 출력("기타")
}
With Blocks
맞춤 상태 {
"활성" => {
출력("활성 상태")
처리하기()
}
"비활성" => 출력("비활성")
_ => 출력("알 수 없음")
}
Pattern Types
| Pattern | Example | Description |
|---|---|---|
| Integer | 42 | Matches exact integer |
| String | "hello" | Matches exact string |
| Boolean | 참, 거짓 | Matches boolean |
| Wildcard | _ | Matches anything |
| Binding | x | Matches anything, binds to variable x |
| Array | [1, 2, 3] | Matches array structure |
Variable Binding
맞춤 값 {
0 => 출력("영")
n => 출력(형식("값: {0}", n))
}
Error Handling
Try / Catch
시도 {
변수 내용 = 파일읽기("없는파일.txt")
출력(내용)
} 처리(오류) {
출력(형식("에러: {0}", 오류))
}
The error variable (오류) contains the error message as a string. V2 errors use Elm-style messaging with source context, so the printed text points back to the original code location.
What Gets Caught
- Division by zero
- File not found
- Index out of bounds
- Undefined variable access
- Type mismatches at runtime
Example: Safe Division
함수 안전나누기(a: 정수, b: 정수) -> 정수 {
시도 {
반환 a / b
} 처리(오류) {
출력(형식("나누기 실패: {0}", 오류))
반환 0
}
}
Example error shape:
타입 오류: 정수를 기대했지만 문자열을 받았습니다
--> main.hgl:3:10
|
3 | 변수 x: 정수 = "hello"
| ^^^^^^^^^^^^^ 여기서 타입이 맞지 않습니다
Modules
Importing Files
포함 "수학도구.hgl"
This executes the file and imports all its definitions (functions, variables, structs) into the current scope.
Duplicate Includes
Han tracks imported files by canonical path and skips duplicate includes.
포함 "utils.hgl"
포함 "./utils.hgl" // same file -> skipped
This keeps include behavior idempotent for repeated module wiring.
Example
수학도구.hgl:
함수 최대값(a: 정수, b: 정수) -> 정수 {
만약 a > b 이면 { 반환 a }
반환 b
}
main.hgl:
포함 "수학도구.hgl"
출력(최대값(10, 20)) // 20
String Methods
| Method | Description | Example | Result |
|---|---|---|---|
.길이() | Character count | "한글".길이() | 2 |
.분리(sep) | Split by separator | "a,b,c".분리(",") | ["a", "b", "c"] |
.포함(s) | Contains substring | "hello".포함("ell") | 참 |
.바꾸기(from, to) | Replace | "hello".바꾸기("l", "r") | "herro" |
.앞뒤공백제거() | Trim whitespace | " hi ".앞뒤공백제거() | "hi" |
.대문자() | Uppercase | "hello".대문자() | "HELLO" |
.소문자() | Lowercase | "HELLO".소문자() | "hello" |
.시작(s) | Starts with | "hello".시작("he") | 참 |
.끝(s) | Ends with | "hello".끝("lo") | 참 |
String Indexing
변수 s = "한글"
출력(s[0]) // 한
출력(s[1]) // 글
String Iteration
반복 글자 안에서 "한글" {
출력(글자)
}
Concatenation
변수 full = "안녕" + "하세요"
출력(full) // 안녕하세요
Array Methods
| Method | Description | Example | Result |
|---|---|---|---|
.추가(값) | Append | arr.추가(6) | mutates in place |
.삭제(인덱스) | Remove at index | arr.삭제(0) | returns removed value |
.길이() | Length | arr.길이() | 5 |
.포함(값) | Contains | arr.포함(3) | 참 |
.역순() | Reverse | arr.역순() | new reversed array |
.정렬() | Sort | arr.정렬() | new sorted array |
.합치기(구분자) | Join to string | arr.합치기(", ") | "1, 2, 3" |
HashMap / Dictionary
Creating a Map
변수 점수 = 사전("수학", 95, "영어", 88, "과학", 92)
변수 빈맵 = 사전()
Arguments are key-value pairs: 사전(key1, val1, key2, val2, ...).
Access and Mutation
출력(점수["수학"]) // 95
점수["국어"] = 100 // add new key
점수["수학"] = 99 // update existing
Methods
| Method | Description | Example |
|---|---|---|
.키목록() | All keys as array | 점수.키목록() → ["수학", "영어", "과학"] |
.값목록() | All values as array | 점수.값목록() → [95, 88, 92] |
.길이() | Number of entries | 점수.길이() → 3 |
.포함(키) | Key exists | 점수.포함("수학") → 참 |
.삭제(키) | Remove key | 점수.삭제("영어") |
Iteration
변수 키들 = 점수.키목록()
반복 키 안에서 키들 {
출력(형식("{0}: {1}", 키, 점수[키]))
}
I/O
Output
출력("안녕하세요") // print to stdout
출력(42) // prints any value
출력("이름:", 이름) // multiple args, space-separated
출력오류("에러 메시지") // print to stderr
Input
변수 이름 = 입력()
출력(형식("안녕, {0}!", 이름))
입력() reads one line from stdin and returns it as a string.
Math Functions
| Function | Description | Example | Result |
|---|---|---|---|
제곱근(x) | Square root | 제곱근(16.0) | 4.0 |
절댓값(x) | Absolute value | 절댓값(-5) | 5 |
거듭제곱(밑, 지수) | Power | 거듭제곱(2, 10) | 1024.0 |
사인(x) | Sine | 사인(파이() / 2.0) | 1.0 |
코사인(x) | Cosine | 코사인(0.0) | 1.0 |
탄젠트(x) | Tangent | ||
로그(x) | Natural log (ln) | 로그(자연상수()) | 1.0 |
로그10(x) | Log base 10 | ||
지수(x) | e^x | 지수(1.0) | 2.718... |
올림(x) | Ceiling | 올림(2.3) | 3.0 |
내림(x) | Floor | 내림(2.9) | 2.0 |
반올림(x) | Round | 반올림(2.5) | 3.0 |
최대(a, b) | Maximum | 최대(3, 7) | 7.0 |
최소(a, b) | Minimum | ||
난수() | Random 0~1 | ||
난수(a, b) | Random int a~b | 난수(1, 10) | |
파이() | Pi constant | 3.14159... | |
자연상수() | Euler's number | 2.71828... | |
행렬곱(A, B) | Matrix multiply | 행렬곱(A, B) | [[실수]] |
전치(A) | Matrix transpose | 전치(A) | [[실수]] |
스칼라곱(A, s) | Scalar multiply | 스칼라곱(A, 2.0) | [[실수]] |
행렬합(A, B) | Matrix addition | 행렬합(A, B) | [[실수]] |
행렬차(A, B) | Matrix subtraction | 행렬차(A, B) | [[실수]] |
내적(a, b) | Dot product | 내적([1,2], [3,4]) | 11.0 |
외적(a, b) | Cross product (3D) | 외적([1,0,0], [0,1,0]) | [0,0,1] |
단위행렬(n) | Identity matrix | 단위행렬(3) | [[1,0,0],...] |
텐서곱(A, B) | Tensor/Kronecker product | 텐서곱(A, B) | [[실수]] |
All math functions accept both 정수 and 실수 inputs.
Matrix Operations
행렬곱 and 전치 work with 2D arrays (array of arrays):
변수 A = [[1.0, 2.0], [3.0, 4.0]]
변수 B = [[5.0, 6.0], [7.0, 8.0]]
변수 결과 = 행렬곱(A, B)
// [[19.0, 22.0], [43.0, 50.0]]
변수 T = 전치(A)
// [[1.0, 3.0], [2.0, 4.0]]
These can be used to implement algorithms like self-attention (Attention(Q,K,V) = softmax(QK^T / √d_k) × V). See examples/어텐션.hgl for a full implementation.
Type Conversion
| Function | Description | Example | Result |
|---|---|---|---|
정수변환(x) | Convert to integer | 정수변환("42") | 42 |
실수변환(x) | Convert to float | 실수변환(42) | 42.0 |
길이(s) | String length | 길이("한글") | 2 |
Conversion Rules
정수변환(3.14) // 3 (truncates)
정수변환("42") // 42 (parse string)
정수변환(참) // 1
정수변환(거짓) // 0
실수변환(42) // 42.0
실수변환("3.14") // 3.14
Format Strings
Positional Arguments
형식("이름: {0}, 나이: {1}", "홍길동", 30)
// → "이름: 홍길동, 나이: 30"
Named Arguments (from scope)
변수 이름 = "홍길동"
변수 나이 = 30
형식("이름: {이름}, 나이: {나이}")
// → "이름: 홍길동, 나이: 30"
String Interpolation
변수 이름 = "홍길동"
출력("${이름}님 안녕하세요")
// desugars to: 출력(형식("{0}님 안녕하세요", 이름))
Named mode substitutes {변수명} with the variable's value from the current scope. Interpolated strings are automatically desugared to 형식().
출력("합: ${1 + 2}")
// desugars to: 출력(형식("합: {0}", 1 + 2))
Use interpolation for simple expressions. 형식() remains the most explicit option for complex templates.
File I/O
| Function | Description | Example |
|---|---|---|
파일읽기(경로) | Read file to string | 파일읽기("data.txt") |
파일쓰기(경로, 내용) | Write string to file | 파일쓰기("out.txt", "hello") |
파일추가(경로, 내용) | Append to file | 파일추가("log.txt", "line\n") |
파일존재(경로) | Check if file exists | 파일존재("data.txt") → 참/거짓 |
Example: Read and Process
시도 {
변수 내용 = 파일읽기("data.txt")
변수 줄들 = 내용.분리("\n")
반복 줄 안에서 줄들 {
출력(줄)
}
} 처리(오류) {
출력(형식("파일 오류: {0}", 오류))
}
JSON
Powered by Rust's serde_json crate.
Parse JSON
변수 텍스트 = "{\"이름\": \"홍길동\", \"나이\": 30}"
변수 데이터 = 제이슨_파싱(텍스트)
출력(데이터["이름"]) // 홍길동
출력(데이터["나이"]) // 30
JSON objects become 사전, arrays become 배열.
Generate JSON
변수 사용자 = 사전("이름", "홍길동", "나이", 30)
변수 json = 제이슨_생성(사용자)
출력(json) // {"나이":30,"이름":"홍길동"}
Pretty Print
변수 예쁜 = 제이슨_예쁘게(사용자)
출력(예쁜)
Functions
| Function | Description |
|---|---|
제이슨_파싱(문자열) | Parse JSON string → Han value |
제이슨_생성(값) | Han value → JSON string |
제이슨_예쁘게(값) | Han value → pretty-printed JSON |
HTTP
Powered by Rust's reqwest crate (blocking mode).
GET Request
변수 응답 = HTTP_포함("https://httpbin.org/get")
출력(응답)
POST Request
변수 본문 = 제이슨_생성(사전("이름", "홍길동"))
변수 응답 = HTTP_보내기("https://httpbin.org/post", 본문)
출력(응답)
POST sends with Content-Type: application/json. If the body is not a string, it's auto-converted to JSON.
Error Handling
시도 {
변수 응답 = HTTP_포함("https://invalid-url.example")
} 처리(오류) {
출력(형식("HTTP 오류: {0}", 오류))
}
Functions
| Function | Description |
|---|---|
HTTP_포함(url) | GET request → response body as string |
HTTP_보내기(url, body) | POST request with JSON body → response as string |
Regex
Powered by Rust's regex crate.
Find All Matches
변수 결과 = 정규식_찾기("[0-9]+", "abc 123 def 456")
출력(결과) // [123, 456]
Test Match
출력(정규식_일치("^[0-9]+$", "12345")) // 참
출력(정규식_일치("^[0-9]+$", "abc")) // 거짓
Replace
변수 결과 = 정규식_바꾸기("[0-9]+", "전화: 010-1234-5678", "***")
출력(결과) // 전화: ***-***-***
Functions
| Function | Description |
|---|---|
정규식_찾기(패턴, 텍스트) | Find all matches → array of strings |
정규식_일치(패턴, 텍스트) | Test if pattern matches → bool |
정규식_바꾸기(패턴, 텍스트, 대체) | Replace all matches → string |
Date & Time
Powered by Rust's chrono crate.
Current Time
출력(현재시간()) // 2025-03-15 12:30:45
출력(현재날짜()) // 2025-03-15
출력(타임스탬프()) // 1710500000 (Unix timestamp)
Functions
| Function | Return | Example |
|---|---|---|
현재시간() | 문자열 | "2025-03-15 12:30:45" |
현재날짜() | 문자열 | "2025-03-15" |
타임스탬프() | 정수 | 1710500000 |
현재시간() and 현재날짜() use local time. 타임스탬프() returns UTC Unix timestamp.
System & Process
Shell Command
변수 결과 = 실행("ls -la")
출력(결과)
Runs the command via sh -c and returns stdout as a string.
Environment Variables
변수 홈 = 환경변수("HOME")
출력(홈) // /Users/username
변수 없는변수 = 환경변수("NONEXISTENT")
출력(없는변수) // 없음
Returns 없음 if the variable doesn't exist.
CLI Arguments
변수 인자들 = 명령인자()
반복 인자 안에서 인자들 {
출력(인자)
}
Returns arguments passed after the filename: hgl interpret file.hgl arg1 arg2
Sleep
잠자기(1000) // sleep 1 second (1000 milliseconds)
Type Introspection
출력(타입(42)) // 정수
출력(타입("hello")) // 문자열
출력(타입([1,2,3])) // 배열
출력(타입(사전())) // 사전
출력(타입(참)) // 불
Functions
| Function | Description |
|---|---|
실행(명령어) | Run shell command → stdout string |
환경변수(이름) | Get env var → string or 없음 |
명령인자() | CLI args → array of strings |
잠자기(밀리초) | Sleep for N milliseconds |
타입(값) | Type name → string |
출력오류(값) | Print to stderr |
CLI Usage
hgl interpret <file.hgl> Run with interpreter
hgl build <file.hgl> Compile to native binary
hgl run <file.hgl> Compile and run immediately
hgl check <file.hgl> Type-check only (no execution)
hgl init [name] Create new Han project
hgl repl Interactive REPL
hgl lsp Start LSP server
Examples
hgl interpret examples/피보나치.hgl
hgl check examples/합계.hgl
hgl build examples/합계.hgl && ./합계
hgl init hello-han
hgl repl
hgl check (Type Check Only)
hgl check parses and type-checks a file without running interpreter/codegen.
hgl check examples/합계.hgl
- Success: prints
✓ 타입 검사 통과 - Failure: prints parser/type diagnostics and exits with non-zero status
hgl init (Project Scaffold)
hgl init hello-han
Creates:
hello-han/main.hglhello-han/.gitignore
Default main.hgl prints 안녕하세요!.
VS Code Extension
Install from Source
cd editors/vscode
npm install
npm run compile
Press F5 in VS Code to launch with the extension loaded.
Features
- Syntax highlighting for
.hglfiles - Keyword, type, builtin, string, number, comment coloring
- Auto-closing brackets and quotes
- LSP integration (hover docs + completion)
LSP Setup
Make sure hgl is in your PATH:
cargo install --path .
The extension automatically starts hgl lsp when you open a .hgl file.
Architecture
Compiler Pipeline
Source (.hgl)
│
▼
┌─────────────┐
│ Lexer │ Source text → Token stream
│ (lexer.rs) │ "함수" → Token::함수
└──────┬──────┘
▼
┌─────────────┐
│ Parser │ Token stream → AST
│ (parser.rs) │ Recursive descent, precedence climbing
└──────┬──────┘
▼
┌─────────────┐
│ AST │ Tree representation of the program
│ (ast.rs) │ Expr, StmtKind, Pattern, Type
└──────┬──────┘
│
├─────────────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Interpreter │ │ CodeGen │
│(interpreter)│ │(codegen.rs) │
│ │ │ │
│ Tree-walking│ │ LLVM IR text│
│ execution │ │ generation │
└─────────────┘ └──────┬──────┘
▼
clang → Binary
Source Files
| File | Lines | Purpose |
|---|---|---|
lexer.rs | ~550 | Tokenization, Korean keyword recognition |
parser.rs | ~1280 | Recursive descent parser, precedence climbing |
ast.rs | ~270 | AST node definitions (Expr, Stmt, Type, Pattern) |
interpreter.rs | ~1760 | Tree-walking interpreter, builtins, methods |
codegen.rs | ~1430 | LLVM IR text generation (Korean→ASCII sanitization) |
typechecker.rs | ~280 | Compile-time type checker (warning mode) |
lsp.rs | ~330 | LSP server (hover, completion) |
main.rs | ~310 | CLI entry point (clap) |
builtins/ | — | Builtin function catalog (math, io, string, system) |
Builtin Module Structure
src/builtins/
├── mod.rs — module declarations
├── math.rs — 제곱근, 절댓값, 거듭제곱, 정수변환, 실수변환, 행렬곱, 전치
├── io.rs — 출력, 입력, 형식, 파일읽기/쓰기
├── string.rs — 길이, 분리, 포함, 바꾸기, 대문자, 소문자
└── system.rs — 실행, HTTP, 정규식, 제이슨, 날짜/시간
Codegen: Korean Identifier Handling
LLVM IR only allows ASCII identifiers. Han's codegen sanitizes Korean variable and function names using Unicode hex encoding:
변수 두배 = ... → %var_uB450uBC30 = alloca i64
함수 인사() { } → define void @uc778uc0ac() { }
This allows Korean-named functions and variables to compile to native binaries.
Token Analysis (AI/LLM)
Benchmark Results
Tested with GPT-4o tokenizer (tiktoken), comparing the same Fibonacci program:
| Language | Tokens |
|---|---|
| Python | 54 |
| JavaScript | 69 |
| Han | 88 |
Why Korean Uses More Tokens
LLM tokenizers use BPE (Byte Pair Encoding):
- Start with raw bytes
- Find the most frequent byte pairs in training data
- Merge them into single tokens
- Repeat
Since training data is predominantly English:
function→ appears billions of times → merged into 1 token함수→ rarely appears → stays as 2-3 byte-level tokens
Per-Keyword Comparison
| Han | Tokens | English | Tokens |
|---|---|---|---|
함수 | 2 | function | 1 |
반환 | 2 | return | 1 |
변수 | 2 | let | 1 |
아니면 | 3 | else | 1 |
멈춰 | 3 | break | 1 |
동안 | 1 | while | 1 |
참 | 1 | true | 1 |
This Is a Tokenizer Problem, Not a Korean Problem
If BPE were trained on a Korean-heavy corpus, 함수 could be a single token. The inefficiency comes from training data distribution, not from the script itself.
Relevant work:
- Ukrainian LLM "Lapa" replaced 80K tokens and achieved 1.5x efficiency for Ukrainian text
- Custom BPE training on Korean programming text could close the gap
Keyword Reference
Control Keywords
| Keyword | English | Syntax |
|---|---|---|
함수 | function | 함수 이름(매개변수: 타입) -> 반환타입 { } |
반환 | return | 반환 값 |
변수 | let (mutable) | 변수 이름 = 값 |
상수 | const | 상수 이름 = 값 |
만약 | if | 만약 조건 이면 { } |
이면 | then/if-then | 만약 조건 이면 { } |
아니면 | else | 아니면 { } or 아니면 조건 이면 { } |
그리고 | and (logical) | a 그리고 b |
또는 | or (logical) | a 또는 b |
반복 | for | 반복 변수 i = 0; i < n; i += 1 { } |
동안 | while | 조건 동안 { } or 동안 조건 { } |
멈춰 | break | 멈춰 |
계속 | continue | 계속 |
안에서 | in (for-in) | 반복 x 안에서 배열 { } |
Type Keywords
| Keyword | English | LLVM |
|---|---|---|
정수 | int | i64 |
실수 | float | f64/double |
문자열 | string | i8* |
불 | bool | i1 |
없음 | void/null | void |
Structure Keywords
| Keyword | English | Syntax |
|---|---|---|
구조 | struct | 구조 이름 { 필드: 타입 } |
구현 | impl | 구현 구조체 { 함수 메서드(자신: T) { } } |
열거 | enum | 열거 이름 { 변형1, 변형2 } |
시도 | try | 시도 { } 처리(오류) { } |
처리 | catch | 처리(오류) { } |
맞춤 | match | 맞춤 값 { 패턴 => 결과 } |
포함 | import | 포함 "파일.hgl" |
Literal Keywords
| Keyword | English |
|---|---|
참 | true |
거짓 | false |
없음 | null/void |
Built-in Functions
| Function | Signature | Description |
|---|---|---|
출력(값) | (any...) -> 없음 | Print to stdout |
입력() | () -> 문자열 | Read line from stdin |
제곱근(x) | (숫자) -> 실수 | Square root |
절댓값(x) | (숫자) -> 숫자 | Absolute value |
거듭제곱(밑, 지수) | (숫자, 숫자) -> 실수 | Power |
정수변환(x) | (any) -> 정수 | Convert to integer |
실수변환(x) | (any) -> 실수 | Convert to float |
길이(s) | (문자열) -> 정수 | String length |
형식(template, ...) | (문자열, any...) -> 문자열 | Format string |
파일읽기(경로) | (문자열) -> 문자열 | Read file |
파일쓰기(경로, 내용) | (문자열, 문자열) -> 없음 | Write file |
파일추가(경로, 내용) | (문자열, 문자열) -> 없음 | Append to file |
파일존재(경로) | (문자열) -> 불 | File exists |
출력오류(값) | (any...) -> 없음 | Print to stderr |
Complete API Reference
This page is optimized for LLM consumption. It contains every keyword, type, builtin, method, and operator in Han in a structured, machine-readable format.
Language: Han (한)
File Extension: .hgl
Execution: hgl interpret <file>, hgl build <file>, hgl check <file>, or hgl init [name]
KEYWORDS
함수 → function definition
반환 → return
변수 → mutable variable (let)
상수 → immutable constant (const)
만약 → if
이면 → then (conditional marker)
아니면 → else
그리고 → logical and
또는 → logical or
반복 → for loop
동안 → while loop
멈춰 → break
계속 → continue
안에서 → in (for-in iteration)
구조 → struct definition
구현 → impl block
열거 → enum definition
시도 → try
처리 → catch
맞춤 → match (pattern matching)
포함 → import
참 → true
거짓 → false
없음 → null/void
TYPES
정수 → i64 (64-bit integer)
실수 → f64 (64-bit float)
문자열 → String (UTF-8)
불 → bool
없음 → void
[정수] → Array of integers
(정수, 문자열) → Tuple
OPERATORS
+ - * / % → arithmetic
== != < > <= >= → comparison
&& || ! → logical
그리고 또는 → Korean logical aliases
|> → pipe operator
= += -= *= /= → assignment
-> → return type arrow
=> → match arm arrow
.. → range (0..10)
:: → enum access (방향::위)
. → field/method access
BUILTIN FUNCTIONS
출력(값...) → print to stdout
입력() → read line from stdin → 문자열
출력오류(값...) → print to stderr
제곱근(x) → sqrt(x) → 실수
절댓값(x) → abs(x) → 숫자
거듭제곱(밑, 지수) → pow(base, exp) → 실수
사인(x) → sin(x) → 실수
코사인(x) → cos(x) → 실수
탄젠트(x) → tan(x) → 실수
로그(x) → ln(x) → 실수
로그10(x) → log10(x) → 실수
지수(x) → e^x → 실수
올림(x) → ceil(x) → 실수
내림(x) → floor(x) → 실수
반올림(x) → round(x) → 실수
최대(a, b) → max(a, b) → 실수
최소(a, b) → min(a, b) → 실수
난수() → random float 0..1 → 실수
난수(a, b) → random int a..b → 정수
파이() → pi constant → 실수
자연상수() → Euler's number → 실수
정수변환(x) → int(x) → 정수
실수변환(x) → float(x) → 실수
길이(s) → len(s) → 정수
행렬곱(A, B) → matrix multiply → [[실수]]
전치(A) → matrix transpose → [[실수]]
스칼라곱(A, s) → scalar multiply → [[실수]]
행렬합(A, B) → matrix addition → [[실수]]
행렬차(A, B) → matrix subtraction → [[실수]]
내적(a, b) → dot product → 실수
외적(a, b) → cross product (3D) → [실수]
단위행렬(n) → identity matrix → [[실수]]
텐서곱(A, B) → tensor/Kronecker product → [[실수]]
형식(template, args...) → format string / interpolation target → 문자열
파일읽기(경로) → read file → 문자열
파일쓰기(경로, 내용) → write file
파일추가(경로, 내용) → append to file
파일존재(경로) → file exists → 불
사전(키, 값, ...) → create HashMap → 사전
제이슨_파싱(문자열) → parse JSON → value
제이슨_생성(값) → value → JSON string
제이슨_예쁘게(값) → value → pretty JSON string
HTTP_포함(url) → GET request → 문자열
HTTP_보내기(url, body) → POST request → 문자열
정규식_찾기(패턴, 텍스트) → find matches → [문자열]
정규식_일치(패턴, 텍스트) → test match → 불
정규식_바꾸기(패턴, 텍스트, 대체) → replace → 문자열
현재시간() → current datetime → 문자열
현재날짜() → current date → 문자열
타임스탬프() → unix timestamp → 정수
실행(명령어) → shell command → 문자열
환경변수(이름) → env var → 문자열 or 없음
명령인자() → CLI args → [문자열]
잠자기(밀리초) → sleep
타입(값) → type name → 문자열
파이썬(코드) → execute Python, return stdout → 문자열
파이썬_값(표현식) → evaluate Python expression → 값
MAP METHODS
.키목록() → all keys → [T]
.값목록() → all values → [T]
.길이() → entry count → 정수
.포함(키) → key exists → 불
.삭제(키) → remove entry → removed value
ARRAY METHODS
.추가(값) → push element
.삭제(인덱스) → remove at index → removed value
.길이() → length → 정수
.포함(값) → contains → 불
.역순() → reversed copy → [T]
.정렬() → sorted copy → [T]
.합치기(구분자) → join to string → 문자열
STRING METHODS
.길이() → character count → 정수
.분리(구분자) → split → [문자열]
.포함(부분) → contains → 불
.바꾸기(전, 후) → replace → 문자열
.앞뒤공백제거() → trim → 문자열
.대문자() → uppercase → 문자열
.소문자() → lowercase → 문자열
.시작(접두사) → starts with → 불
.끝(접미사) → ends with → 불
SYNTAX PATTERNS
// Variable declaration
변수 이름 = 값
변수 이름: 타입 = 값
상수 이름 = 값
// Function
함수 이름(매개변수: 타입) -> 반환타입 {
반환 값
}
// If/else (Korean-default)
만약 조건 이면 {
...
} 아니면 조건2 이면 {
...
} 아니면 {
...
}
// Older minimal form is still supported, but docs prefer the `이면` pattern.
// For loop
반복 변수 i = 0; i < n; i += 1 {
...
}
// For-in
반복 항목 안에서 배열 {
...
}
// While (SOV default)
조건 동안 {
...
}
// While (SVO alternative)
동안 조건 {
...
}
// Struct
구조 이름 {
필드: 타입,
필드2: 타입
}
// Impl
구현 구조체이름 {
함수 메서드(자신: 구조체이름) {
...
}
}
// Enum
열거 이름 {
변형1,
변형2
}
// Match
맞춤 값 {
패턴1 => 결과1
패턴2 => { ... }
_ => 기본값
}
// Try/catch
시도 {
...
} 처리(오류변수) {
...
}
// Import
포함 "파일.hgl"
// Closure
변수 f = 함수(x: 정수) { 반환 x * 2 }
// Tuple
변수 t = (1, "hello", 참)
t.0 // 1
// Range
0..10 // [0, 1, 2, ..., 9]
// Array
변수 arr = [1, 2, 3]
arr[0] // indexing
arr[-1] // negative indexing
arr[0] = 99 // mutation