type literal = String of string | Number of float | Bool of bool | Nil (* [@@deriving show { with_path = false }] *) let show_literal literal = match literal with | String s -> s | Number x -> string_of_float x | Bool b -> string_of_bool b | Nil -> "nil" type binary_op = Plus | Minus | Mul | Div | Equal | Less | Greater | LessEqual | GreaterEqual [@@deriving show { with_path = false }] type unary_op = Neg | Not [@@deriving show { with_path = false }] type expr = | Literal of literal | BinaryExpr of { op : binary_op; left : expr; right : expr } | UnaryExpr of { op : unary_op; expr : expr } (* [@@deriving show { with_path = false }] *) let rec show_expr ?(indent = 0) expr = let show_indented = show_expr ~indent:(indent + 2) in let ident_s = String.make indent ' ' in match expr with | Literal literal -> ident_s ^ show_literal literal | BinaryExpr { op; left; right } -> ident_s ^ show_binary_op op ^ "\n" ^ show_indented left ^ "\n" ^ show_indented right | UnaryExpr { op; expr } -> ident_s ^ show_unary_op op ^ "\n" ^ show_indented expr let make_string (s : string) = Literal (String s) let make_number (x : float) = Literal (Number x) let make_bool (b : bool) = Literal (Bool b) let make_nil () = Literal Nil let make_binary (op : binary_op) (left : expr) (right : expr) = BinaryExpr { op; left; right } let make_unary (op : unary_op) (expr : expr) = UnaryExpr { op; expr }