2. 구문 트리(AST) 구조
하리(Hari) 언어의 추상 구문 트리(AST) 명세입니다.
이 문서는 하리 언어 파서(Parser)가 생성하는 AST(Abstract Syntax Tree)의 노드별 JSON 스키마를 정의하고 있어요. 하리 언어의 인터프리터, 컴파일러, 정적 분석기 등 모든 도구는 이 명세서를 기준으로 구현된답니다.
1. 프로그램 (Program)
모든 소스 코드의 최상위 노드예요.
{
"type": "Program",
"body": [ /* Statement 노드들의 목록 */ ]
}
2. 선언 및 할당 (Declarations & Assignments)
VariableDeclaration (변수 선언 및 값 할당)
('우리'의) '이름'을 ([타입]인) 값으로 정하자/고정하자/준비하자
(참고: 파서는 변수 선언과 값 재할당을 구분하지 않고 모두 이 노드로 파싱하며, 동적 변수 생성인지 재대입인지는 런타임이 결정해요.)
{
"type": "VariableDeclaration",
"target": /* Identifier 또는 MemberExpression (객체의 속성에 할당할 경우) */,
"isStatic": false, // '우리'의 가 붙은 경우 true
"accessModifier": "public", // 클래스 필드인 경우 "public", "private", "protected" 중 하나 (명시되지 않으면 public)
"typeAnnotation": { "type": "TypeReference", "name": "타입" }, // 타입 지정이 없으면 null
"value": /* Expression 노드 (준비하자이거나 속성 접근자인 경우 null) */,
"isConst": false, // '고정하자' 인 경우 true
"isDeclarationOnly": false, // '준비하자' 인 경우 true
"getter": [ /* Statement 노드 목록 (속성 접근자의 '가져올 때' 블록, 없으면 null) */ ],
"setter": {
"param": { "type": "Identifier", "name": "새값" },
"body": [ /* Statement 노드 목록 (속성 접근자의 '정할 때' 블록) */ ]
} // 속성 접근자의 '정할 때' 블록, 없으면 null
}
Compound Assignments (복합 대입 연산)
'이름'에 값을 더하자/빼자 등
{
"type": "CompoundAssignment",
"operator": "+=", // 더하리는 "+=", 빼자는 "-=" 등
"target": /* Identifier 또는 MemberExpression */,
"value": /* Expression 노드 */
}
List Operations (목록 전용 조작)
'목록' (앞에/뒤에/에) 값을 추가하자
{
"type": "ListPushStatement",
"target": /* Identifier 또는 MemberExpression */,
"value": /* Expression 노드 */,
"position": "back" // "front" (앞에), "back" (뒤에/기본값)
}
'목록' (앞에서/뒤에서/에서) 꺼내자
{
"type": "ListPopStatement",
"target": /* Identifier 또는 MemberExpression */,
"position": "back" // "front" (앞에서), "back" (뒤에서/기본값)
}
'목록' (앞에서/뒤에서/에서) 꺼낸 값 (Expression 노드)
{
"type": "ListPopExpression",
"target": /* Identifier 또는 MemberExpression */,
"position": "back" // "front", "back"
}
3. 제어 흐름 (Control Flow)
IfStatement (조건문)
만약 (조건) 면: ... 그렇지 않고 만약 (조건) 면: ... 그렇지 않다면: ...
{
"type": "IfStatement",
"condition": /* Expression 노드 */,
"consequent": [ /* Statement 노드들의 목록 */ ],
"elifs": [
{
"condition": /* Expression 노드 */,
"consequent": [ /* Statement 노드들의 목록 */ ]
}
],
"alternate": [ /* Statement 노드들의 목록 (없으면 빈 목록) */ ]
}
SwitchStatement (스위치문)
'값'에 따라 나누자: "경우1" 인 경우: ... 나머지는: ...
{
"type": "SwitchStatement",
"discriminant": /* Expression 노드 */,
"cases": [
{
"values": [ /* Expression 노드 목록 (쉼표로 여러 조건 가능) */ ],
"body": [ /* Statement 노드 목록 */ ]
}
],
"default": [ /* Statement 노드 목록 (선택 사항, 없으면 null) */ ]
}
FallthroughStatement (스위치 관통)
다음으로 이어가자
{
"type": "FallthroughStatement"
}
WhileLoop (조건 반복문)
(조건) 동안 반복하자:
{
"type": "WhileLoop",
"condition": /* Expression 노드 */,
"body": [ /* Statement 노드 목록 */ ]
}
ForEachLoop (목록 순회)
'목록'의 '항목'마다 반복하자:
{
"type": "ForEachLoop",
"item": { "type": "Identifier", "name": "항목" }, // 순회할 개별 요소의 Identifier 노드
"iterable": /* Expression 노드 (평가 결과가 List 또는 문자열 타입이어야 함) */,
"body": [ /* Statement 노드 목록 */ ]
}
ForRangeStatement (숫자 범위 반복문)
1부터 10까지 반복하자 ('횟수'): 또는 '시작'부터 '끝'까지 반복하자 ('횟수'):
{
"type": "ForRangeStatement",
"start": /* Expression 노드 */,
"end": /* Expression 노드 */,
"iterator": { "type": "Identifier", "name": "횟수" }, // 반복자 변수의 Identifier 노드
"body": [ /* Statement 노드 목록 */ ]
}
BreakStatement (반복문 탈출)
반복을 끝내자
{
"type": "BreakStatement"
}
4. 함수 및 객체지향 (Functions & OOP)
FunctionDeclaration (함수/메서드 선언)
[리턴타입]을 돌려주는 ('우리'의) <함수명>을 만들자 ([타입]인 '인자' = "기본값"):
{
"type": "FunctionDeclaration",
"id": "함수명",
"isStatic": false, // '우리'의 가 붙은 경우 true
"accessModifier": "public", // "public", "private", "protected" 중 하나 (명시되지 않으면 public)
"returnType": { "type": "TypeReference", "name": "리턴타입" }, // 명시되지 않으면 null
"isAbstract": false, // '밑설계' 시 (본문이 없는 경우) true
"params": [
{
"type": { "type": "TypeReference", "name": "타입" }, // 명시되지 않으면 null
"name": "인자이름",
"default": /* Expression 노드 (기본값이 없으면 null) */
}
],
"body": [ /* Statement 노드 목록 (isAbstract가 true이면 null) */ ]
}
ReturnStatement (반환문)
'값'을 돌려주자 또는 돌려주자
{
"type": "ReturnStatement",
"value": /* Expression 노드 (값 생략 시 null) */
}
ClassDeclaration (클래스 선언)
[부모클래스]를 바탕으로 하고 [인터페이스]를 따르는 [(타입)클래스명]을 설계하자/밑설계하자:
{
"type": "ClassDeclaration",
"id": "클래스명",
"typeParams": [ "타입" ], // 제네릭 타입 파라미터 (없으면 빈 목록)
"isAbstract": false, // '밑설계하자' 인 경우 true
"baseClass": { "type": "TypeReference", "name": "부모클래스명" }, // 상속받는 단일 부모 클래스 (없으면 null)
"interfaces": [ /* TypeReference 노드 목록 (없으면 빈 목록) */ ], // 구현하는 인터페이스 리스트
"body": [ /* FunctionDeclaration, ConstructorDeclaration 등 */ ]
}
ConstructorDeclaration (생성자 선언)
처음 만들어질 때 ('인자') 다음과 같이 하자:
{
"type": "ConstructorDeclaration",
"id": { "type": "Identifier", "name": "처음 만들어질 때" },
"params": [ /* FunctionDeclaration과 동일한 파라미터 구조 */ ],
"body": [ /* Statement 노드 목록 */ ]
}
InterfaceDeclaration (인터페이스 선언)
[인터페이스명]을 규정하자:
{
"type": "InterfaceDeclaration",
"id": "인터페이스명",
"body": [ /* InterfaceMethod 노드 목록 */ ]
}
InterfaceMethod (인터페이스 메서드 규약)
<메서드명>이 있어야 한다 ([타입]인 '인자')
{
"type": "InterfaceMethod",
"id": "메서드명",
"returnType": { "type": "TypeReference", "name": "리턴타입" }, // 명시되지 않으면 null
"params": [ /* FunctionDeclaration과 동일한 파라미터 구조 */ ]
}
5. 수식 및 특수 참조 (Expressions & Special References)
BinaryExpression (이항 연산)
A + B, A 가 B 와 같다, A 가 B 의 일종이다 등
{
"type": "BinaryExpression",
"left": /* Expression 노드 */,
"operator": "+", "-", "*", "/", "%", "==", "!=", "<", ">", "<=", ">=", "instanceof" /* 연산자 기호 */,
"right": /* Expression 노드 (단, 연산자가 "instanceof"일 경우 TypeReference 노드) */
}
산술 연산자의 결합 순서는 일반 수학과 같아요. * / %가 + -보다 먼저 묶이고, 같은 단계의 연산자는 왼쪽부터 묶여요. 그래서 2 + 3 * 4는 left: 2, operator: "+", right: (3 * 4)인 트리가 돼요. 소괄호로 묶은 식은 그 자체가 하나의 항이에요.
LogicalExpression (논리 연산)
A 그리고 B, A 또는 B (단락 평가 지원)
{
"type": "LogicalExpression",
"left": /* Expression 노드 */,
"operator": "그리고", "또는",
"right": /* Expression 노드 */
}
CallExpression (함수/메서드 호출)
<함수명>(인자1, 인자2)
{
"type": "CallExpression",
"callee": /* Identifier, MemberExpression, 또는 FunctionReference */,
"arguments": [ /* Expression 노드 목록 */ ]
}
NewExpression (인스턴스 생성)
새로운 [클래스명](인자)
{
"type": "NewExpression",
"callee": {
"type": "TypeReference",
"name": "클래스명"
},
"arguments": [ /* Expression 노드 목록 */ ]
}
MemberExpression (속성/메서드/인덱스 접근)
'객체'의 '속성', '목록'의 1번째, '사전'의 "키"
{
"type": "MemberExpression",
"object": /* Expression 노드 (또는 정적 접근 시 TypeReference 노드) */,
"property": /* Identifier(속성), FunctionReference(메서드), IndexExpression, LengthLiteral, 또는 Literal(문자열 키) */
}
Special References (특수 참조)
부모, 바깥 예약어
// 부모
{
"type": "SuperReference"
}
// 바깥
{
"type": "OuterReference"
}
Identifier (변수명)
'이름'
{
"type": "Identifier",
"name": "이름"
}
FunctionReference (함수 참조)
정적 참조: <함수명>
동적 참조 (리플렉션): <'변수명'> 또는 <"문자열">
{
"type": "FunctionReference",
"name": "함수명", // 정적 참조일 경우 문자열, 동적 참조일 경우 null
"expression": /* Expression 노드 (동적 참조일 경우 Identifier나 Literal 등, 정적 참조 시 null) */
}
ExpressionStatement (수식문)
<함수>()를 실행하자처럼 수식 자체가 하나의 문장(Statement)으로 쓰일 때 사용된답니다.
{
"type": "ExpressionStatement",
"expression": /* CallExpression 등 Expression 노드 */
}
TypeReference (타입 참조)
타입 정보를 나타내는 노드예요.
{
"type": "TypeReference",
"name": "타입명",
"typeArgs": [ /* TypeReference 노드 목록 (제네릭 인자, 없으면 빈 목록) */ ]
}
Literal (기본 리터럴)
숫자, 문자열, 논리값(참, 거짓), 널(비어있음) 리터럴 (템플릿 제외)
{
"type": "Literal",
"value": 42 /* 평가된 호스트 언어의 원시 값 (예: 42, "안녕", true, false, null) */,
"raw": "42" /* 소스 코드 문자열 (예: "42", "\"안녕\"", "참", "비어있음") */
}
TemplateLiteral (템플릿 리터럴)
틀"문자열 {'변수'} 문자열"
{
"type": "TemplateLiteral",
"strings": [ "문자열 ", " 문자열" ],
"expressions": [ /* 내포된 Expression 노드 목록 */ ]
}
ListLiteral (목록)
[1, 2, 3]
{
"type": "ListLiteral",
"elements": [ /* Expression 노드 목록 */ ]
}
DictLiteral (사전)
{"키": "값"}
{
"type": "DictLiteral",
"elements": [
{
"key": /* Expression 노드 */,
"value": /* Expression 노드 */
}
]
}
IndexExpression (인덱스 접근식)
1번째, '인덱스변수'번째 (여기서 번째는 인덱싱을 의미하는 필수 문법 토큰이며, 가독성을 위해 뒤에 붙는 값(1번째 값) 같은 단어는 파서가 무시하는 옵션 토큰(Syntactic Sugar)이에요.)
{
"type": "IndexExpression",
"index": /* Expression 노드 (평가 결과가 반드시 정수여야 함) */
}
LengthLiteral (길이)
길이
{
"type": "LengthLiteral",
"value": "길이"
}
6. 모듈 및 예외 (Modules & Exceptions)
ImportStatement (모듈 가져오기)
"파일"에서 전부 가져오자 또는 [모듈]에서 <함수>와 <함수2>를 가져오자
{
"type": "ImportStatement",
"module": {
"kind": "user", // "user" (문자열 리터럴 파일) 또는 "builtin" (타입 리터럴 내장 모듈)
"name": "파일이나모듈명"
},
"imports": null // 전부 가져올 때는 null, 특정 항목만 가져올 때는 목록 ["함수명", "변수명"]
}
현재 하자·카나데 구현은 항목 목록과 전부 여부를 이렇게 가져요. 항목은 <a>와 <b>를 가져오자처럼 조사로 이어 쓰고(카나데는 と), 별칭(<올림>을 <반올림>으로)은 항목이 하나일 때만 붙일 수 있어요. [모듈]에서 전부 가져오자는 그 모듈이 선언한 함수·클래스·인터페이스(내장 모듈은 함수 전부)를 가져와요.
타입 리터럴([이름])로 쓴 모듈은 표준 라이브러리, Hana 런타임과 함께 배포하는 패키지, 설치한 서드파티 패키지 중 하나예요. 서드파티 패키지의 이름은 [github.com/주인/저장소]처럼 git 경로이고, 어느 쪽인지는 모듈을 불러오는 쪽(로더)이 정해요. 파서는 [이름]을 모두 builtin으로 읽어요. 가져온 함수가 그 모듈 안의 다른 함수를 부를 수 있다는 것(모듈 범위)은 런타임 명세 4.3에 있어요.
TryStatement (예외 처리문)
일단 해보자: ... 오류가 발생했다면 ('에러'): ... 마무리는 항상: ...
{
"type": "TryStatement",
"block": [ /* Statement 노드 목록 (try 블록) */ ],
"handlers": [ /* CatchClause 노드 배열 (순서대로 평가됨) */ ],
"finalizer": [ /* Statement 노드 목록 (finally 블록) */ ] // 없으면 null
}
CatchClause (개별 예외 처리 블록)
[오류타입]이 발생했다면 ('에러'): 또는 오류가 발생했다면 ('에러'):
{
"type": "CatchClause",
"catchType": { "type": "TypeReference", "name": "오류타입" }, // 타입 지정이 없으면 null (모든 예외를 잡음)
"param": { "type": "Identifier", "name": "에러식별자명" },
"body": [ /* Statement 노드 목록 */ ]
}
ThrowStatement (오류 발생)
[오류]("메시지")를 발생시키자
{
"type": "ThrowStatement",
"error": /* Expression 노드 (보통 NewExpression으로 생성된 예외 객체) */
}
7. 입출력 및 기타 (I/O & Others)
PrintStatement (출력문)
"메시지"를 출력하자
{
"type": "PrintStatement",
"value": /* Expression 노드 */
}
PrintInlineStatement (이어 출력문)
"메시지"를 이어출력하자
{
"type": "PrintInlineStatement",
"value": /* Expression 노드 */
}
InputStatement (입력문)
'변수'를 [타입]으로 입력받자 또는 '변수'를 입력받자
{
"type": "InputStatement",
"target": { "type": "Identifier", "name": "변수" }, // 입력값을 저장할 변수의 Identifier 노드
"typeAnnotation": { "type": "TypeReference", "name": "타입" } // 기대하는 타입 (생략 시 기본적으로 "문자열")
}