Files
coollang/lib/ast.ml
T
coolguyandClaude Opus 5 801a7b330b modules: 모듈 경계, interface hash, 그리고 고정점 invalidation
되돌리기 비싼 결정 중 마지막 하나 — incremental 아키텍처 — 를 코드와
테스트로 닫는다.

- iface.ml: exported surface 추출과 해시. 별칭 한정(qualify)은 소비 시점에만
  일어나므로 가져오는 쪽의 별칭이 정의 모듈의 hash에 새지 않는다.
- session.ml: 모듈 로딩과 고정점 전파. hash 비교가 dependents 재검사보다
  앞선다 — 이 순서가 "본문만 수정 시 downstream 0건"의 전부다.
- 한정 이름(Alias.Type, Alias.Ctor, Alias.fn)을 타입 검사, 패턴, 소진성,
  move 검사가 모두 하나의 키("Alias.name")로 본다.
- 패키지 경로(cool.dev/std/list)는 v0에서 해소하지 않고 불투명하게 둔다.
  없다고 말하지 않는다.
- 회귀 테스트: 본문만 고치면 자기 자신만 재검사(1건), variant를 추가하면
  downstream까지 전파되고 실제로 소진성이 깨진다(2건).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
2026-08-30 14:11:30 +09:00

486 lines
13 KiB
OCaml

(* 구문 트리. grammar.ebnf의 프로덕션과 일대일로 대응한다.
모든 노드가 위치를 들고 다닌다. *)
type pos = Token.pos
type lit = L_int of string | L_str of string | L_bool of bool
type eff_name = { cap : string; meth : string }
(* eff_atom: 변수 단독 또는 리터럴 집합. 합집합은 여기 없다 —
결과 위치에서만 eff_atom의 목록으로 나타난다. *)
type eff_atom = Eff_var of string | Eff_set of eff_name list
type eff_result = eff_atom list (* 합집합. 길이 1이면 단일 *)
type ty =
(* modl: 다른 모듈의 타입은 별칭으로 한정한다 (Shapes.Shape).
한정하지 않으면 이 모듈의 이름이다 — 암묵적으로 끌어오지 않는다. *)
| T_named of {
modl : string option;
name : string;
args : targ list;
pos : pos;
}
| T_fn of {
affine : bool;
params : ty list;
eff : eff_atom option;
ret : ty option;
pos : pos;
}
(* 제네릭 인자는 타입 또는 effect다. 맨 이름은 둘 다일 수 있으므로
파서는 타입으로 읽고 이름 해소가 판정한다. *)
and targ = TA_ty of ty | TA_eff of eff_atom
type pattern =
| P_wild of pos
| P_lit of lit * pos
| P_bind of string * pos
| P_ctor of {
modl : string option;
name : string;
args : pattern list;
pos : pos;
}
type unop = U_not | U_neg
type binop =
| B_or
| B_and
| B_eq
| B_ne
| B_lt
| B_le
| B_gt
| B_ge
| B_add
| B_sub
| B_mul
| B_div
| B_rem
type expr =
| E_lit of lit * pos
| E_ident of string * pos
| E_list of expr list * pos
| E_struct of { name : string; fields : (string * expr) list; pos : pos }
| E_closure of closure
| E_if of { cond : expr; then_ : block; else_ : expr option; pos : pos }
| E_match of { scrutinee : expr; arms : arm list; pos : pos }
| E_scope of { name : string; parent : string; body : block; pos : pos }
| E_block of block
| E_call of { callee : expr; args : expr list; pos : pos }
| E_field of { obj : expr; name : string; pos : pos }
| E_inst of { callee : expr; args : targ list; pos : pos }
| E_try of { inner : expr; pos : pos }
| E_unary of { op : unop; operand : expr; pos : pos }
| E_binary of { op : binop; lhs : expr; rhs : expr; pos : pos }
and closure = {
cl_params : (string * ty option) list;
cl_eff : eff_atom option;
cl_ret : ty option;
cl_body : block;
cl_pos : pos;
}
and arm = { arm_pat : pattern; arm_body : expr; arm_pos : pos }
and block = { stmts : stmt list; block_pos : pos }
and stmt =
| S_let of {
mut_ : bool;
pat : pattern;
ty : ty option;
value : expr;
pos : pos;
}
| S_return of { value : expr option; pos : pos }
| S_assign of { place : expr; value : expr; pos : pos }
| S_expr of expr
type gen_param = { gp_name : string; gp_effect : bool; gp_pos : pos }
type param = {
p_own : bool;
p_mut : bool;
p_name : string;
p_ty : ty;
p_pos : pos;
}
type fn_decl = {
fn_name : string;
fn_gen : gen_param list;
fn_params : param list;
fn_eff : eff_result option;
fn_ret : ty option;
fn_body : block option;
fn_pos : pos;
}
type field = { f_name : string; f_ty : ty; f_pos : pos }
type variant = { v_name : string; v_args : ty list; v_pos : pos }
type item =
| I_import of { path : string; alias : string; pos : pos }
| I_reexport of { name : string; pos : pos }
| I_fn of { pub : bool; decl : fn_decl }
| I_struct of {
pub : bool;
copyable : bool;
name : string;
gen : gen_param list;
fields : field list;
pos : pos;
}
| I_enum of {
pub : bool;
name : string;
gen : gen_param list;
variants : variant list;
pos : pos;
}
| I_capability of {
pub : bool;
name : string;
methods : fn_decl list;
pos : pos;
}
| I_const of { pub : bool; name : string; ty : ty; value : expr; pos : pos }
type modul = { items : item list }
(* ------------------------------------------------------------------ *)
(* 출력 — 디버깅과 테스트용 s-식 *)
(* ------------------------------------------------------------------ *)
let buf_lit b = function
| L_int s -> Buffer.add_string b s
| L_str s -> Buffer.add_string b (Printf.sprintf "%S" s)
| L_bool v -> Buffer.add_string b (if v then "true" else "false")
let buf_list b f sep xs =
List.iteri
(fun i x ->
if i > 0 then Buffer.add_string b sep;
f x)
xs
let buf_eff_atom b = function
| Eff_var v -> Buffer.add_string b ("evar " ^ v)
| Eff_set names ->
Buffer.add_string b "eset";
List.iter
(fun { cap; meth } -> Buffer.add_string b (" " ^ cap ^ "." ^ meth))
names
let rec buf_ty b = function
| T_named { modl; name; args; _ } ->
let name = match modl with None -> name | Some m -> m ^ "." ^ name in
if args = [] then Buffer.add_string b name
else (
Buffer.add_string b ("(" ^ name);
List.iter
(fun a ->
Buffer.add_char b ' ';
buf_targ b a)
args;
Buffer.add_char b ')')
| T_fn { affine; params; eff; ret; _ } ->
Buffer.add_string b (if affine then "(affine-fn (" else "(fn (");
buf_list b (buf_ty b) " " params;
Buffer.add_char b ')';
(match eff with
| None -> ()
| Some e ->
Buffer.add_string b " [";
buf_eff_atom b e;
Buffer.add_char b ']');
(match ret with
| None -> ()
| Some t ->
Buffer.add_string b " -> ";
buf_ty b t);
Buffer.add_char b ')'
and buf_targ b = function
| TA_ty t -> buf_ty b t
| TA_eff e ->
Buffer.add_char b '[';
buf_eff_atom b e;
Buffer.add_char b ']'
let rec buf_pattern b = function
| P_wild _ -> Buffer.add_char b '_'
| P_lit (l, _) -> buf_lit b l
| P_bind (n, _) -> Buffer.add_string b n
| P_ctor { modl; name; args; _ } ->
let name = match modl with None -> name | Some m -> m ^ "." ^ name in
Buffer.add_string b ("(" ^ name);
List.iter
(fun p ->
Buffer.add_char b ' ';
buf_pattern b p)
args;
Buffer.add_char b ')'
let unop_name = function U_not -> "!" | U_neg -> "-"
let binop_name = function
| B_or -> "||"
| B_and -> "&&"
| B_eq -> "=="
| B_ne -> "!="
| B_lt -> "<"
| B_le -> "<="
| B_gt -> ">"
| B_ge -> ">="
| B_add -> "+"
| B_sub -> "-"
| B_mul -> "*"
| B_div -> "/"
| B_rem -> "%"
let rec buf_expr b = function
| E_lit (l, _) -> buf_lit b l
| E_ident (n, _) -> Buffer.add_string b n
| E_list (xs, _) ->
Buffer.add_string b "(list";
List.iter
(fun e ->
Buffer.add_char b ' ';
buf_expr b e)
xs;
Buffer.add_char b ')'
| E_struct { name; fields; _ } ->
Buffer.add_string b ("(struct " ^ name);
List.iter
(fun (n, e) ->
Buffer.add_string b (" (" ^ n ^ " ");
buf_expr b e;
Buffer.add_char b ')')
fields;
Buffer.add_char b ')'
| E_closure c ->
Buffer.add_string b "(closure (";
buf_list b
(fun (n, t) ->
Buffer.add_string b n;
match t with
| None -> ()
| Some t ->
Buffer.add_char b ':';
buf_ty b t)
" " c.cl_params;
Buffer.add_string b ") ";
buf_block b c.cl_body;
Buffer.add_char b ')'
| E_if { cond; then_; else_; _ } ->
Buffer.add_string b "(if ";
buf_expr b cond;
Buffer.add_char b ' ';
buf_block b then_;
(match else_ with
| None -> ()
| Some e ->
Buffer.add_char b ' ';
buf_expr b e);
Buffer.add_char b ')'
| E_match { scrutinee; arms; _ } ->
Buffer.add_string b "(match ";
buf_expr b scrutinee;
List.iter
(fun a ->
Buffer.add_string b " (";
buf_pattern b a.arm_pat;
Buffer.add_string b " => ";
buf_expr b a.arm_body;
Buffer.add_char b ')')
arms;
Buffer.add_char b ')'
| E_scope { name; parent; body; _ } ->
Buffer.add_string b ("(scope " ^ name ^ " = " ^ parent ^ " ");
buf_block b body;
Buffer.add_char b ')'
| E_block bl -> buf_block b bl
| E_call { callee; args; _ } ->
Buffer.add_string b "(call ";
buf_expr b callee;
List.iter
(fun e ->
Buffer.add_char b ' ';
buf_expr b e)
args;
Buffer.add_char b ')'
| E_field { obj; name; _ } ->
Buffer.add_string b "(. ";
buf_expr b obj;
Buffer.add_string b (" " ^ name ^ ")")
| E_inst { callee; args; _ } ->
Buffer.add_string b "(inst ";
buf_expr b callee;
List.iter
(fun a ->
Buffer.add_char b ' ';
buf_targ b a)
args;
Buffer.add_char b ')'
| E_try { inner; _ } ->
Buffer.add_string b "(? ";
buf_expr b inner;
Buffer.add_char b ')'
| E_unary { op; operand; _ } ->
Buffer.add_string b ("(" ^ unop_name op ^ " ");
buf_expr b operand;
Buffer.add_char b ')'
| E_binary { op; lhs; rhs; _ } ->
Buffer.add_string b ("(" ^ binop_name op ^ " ");
buf_expr b lhs;
Buffer.add_char b ' ';
buf_expr b rhs;
Buffer.add_char b ')'
and buf_block b { stmts; _ } =
Buffer.add_string b "(block";
List.iter
(fun s ->
Buffer.add_char b ' ';
buf_stmt b s)
stmts;
Buffer.add_char b ')'
and buf_stmt b = function
| S_let { mut_; pat; ty; value; _ } ->
Buffer.add_string b (if mut_ then "(let-mut " else "(let ");
buf_pattern b pat;
(match ty with
| None -> ()
| Some t ->
Buffer.add_char b ':';
buf_ty b t);
Buffer.add_char b ' ';
buf_expr b value;
Buffer.add_char b ')'
| S_return { value; _ } -> (
Buffer.add_string b "(return";
match value with
| None -> Buffer.add_char b ')'
| Some e ->
Buffer.add_char b ' ';
buf_expr b e;
Buffer.add_char b ')')
| S_assign { place; value; _ } ->
Buffer.add_string b "(set ";
buf_expr b place;
Buffer.add_char b ' ';
buf_expr b value;
Buffer.add_char b ')'
| S_expr e -> buf_expr b e
let buf_gen b gen =
if gen <> [] then (
Buffer.add_string b " <";
buf_list b
(fun g ->
Buffer.add_string b
(if g.gp_effect then g.gp_name ^ ":effects" else g.gp_name))
" " gen;
Buffer.add_char b '>')
let buf_fn b (d : fn_decl) =
Buffer.add_string b ("(fn " ^ d.fn_name);
buf_gen b d.fn_gen;
Buffer.add_string b " (";
buf_list b
(fun p ->
if p.p_own then Buffer.add_string b "own ";
if p.p_mut then Buffer.add_string b "mut ";
Buffer.add_string b (p.p_name ^ ":");
buf_ty b p.p_ty)
" " d.fn_params;
Buffer.add_char b ')';
(match d.fn_eff with
| None -> ()
| Some atoms ->
Buffer.add_string b " [";
buf_list b (fun a -> buf_eff_atom b a) " | " atoms;
Buffer.add_char b ']');
(match d.fn_ret with
| None -> ()
| Some t ->
Buffer.add_string b " -> ";
buf_ty b t);
(match d.fn_body with
| None -> Buffer.add_string b " decl"
| Some bl ->
Buffer.add_char b ' ';
buf_block b bl);
Buffer.add_char b ')'
let buf_item b = function
| I_import { path; alias; _ } ->
Buffer.add_string b (Printf.sprintf "(import %S as %s)" path alias)
| I_reexport { name; _ } -> Buffer.add_string b ("(reexport " ^ name ^ ")")
| I_fn { pub; decl } ->
if pub then Buffer.add_string b "pub ";
buf_fn b decl
| I_struct { pub; copyable; name; gen; fields; _ } ->
if pub then Buffer.add_string b "pub ";
if copyable then Buffer.add_string b "copyable ";
Buffer.add_string b ("(struct " ^ name);
buf_gen b gen;
List.iter
(fun f ->
Buffer.add_string b (" (" ^ f.f_name ^ " ");
buf_ty b f.f_ty;
Buffer.add_char b ')')
fields;
Buffer.add_char b ')'
| I_enum { pub; name; gen; variants; _ } ->
if pub then Buffer.add_string b "pub ";
Buffer.add_string b ("(enum " ^ name);
buf_gen b gen;
List.iter
(fun v ->
Buffer.add_string b (" (" ^ v.v_name);
List.iter
(fun t ->
Buffer.add_char b ' ';
buf_ty b t)
v.v_args;
Buffer.add_char b ')')
variants;
Buffer.add_char b ')'
| I_capability { pub; name; methods; _ } ->
if pub then Buffer.add_string b "pub ";
Buffer.add_string b ("(capability " ^ name);
List.iter
(fun m ->
Buffer.add_char b ' ';
buf_fn b m)
methods;
Buffer.add_char b ')'
| I_const { pub; name; ty; value; _ } ->
if pub then Buffer.add_string b "pub ";
Buffer.add_string b ("(const " ^ name ^ ":");
buf_ty b ty;
Buffer.add_char b ' ';
buf_expr b value;
Buffer.add_char b ')'
let show_item item =
let b = Buffer.create 256 in
buf_item b item;
Buffer.contents b
let show_expr e =
let b = Buffer.create 128 in
buf_expr b e;
Buffer.contents b
let show_ty t =
let b = Buffer.create 64 in
buf_ty b t;
Buffer.contents b