### Install ClangML with Dependencies using Opam Source: https://github.com/ocamllibs/clangml/blob/main/README.md Use the opam depext plugin to install clangml along with its system dependencies. This is the recommended method for installation. ```bash opam depext -i clangml ``` -------------------------------- ### Pin ClangML Snapshot and Install Dependencies Source: https://github.com/ocamllibs/clangml/blob/main/README.md This command pins the clangml snapshot from GitHub and then uses opam depext to install clangml and its dependencies. The -n option prevents opam pin from installing clangml directly, and -i tells opam depext to install clangml after dependencies are met. ```bash opam pin add -n git+https://github.com/thierry-martinez/clangml.git#snapshot opam depext -i clangml ``` -------------------------------- ### Get Type Size and Alignment with ClangML Source: https://context7.com/ocamllibs/clangml/llms.txt Retrieve the size and alignment of a type associated with an AST node. This is useful for understanding memory layout. The size and alignment are returned in bits. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "struct S { int a; double b; }; struct S s;" let () = (* Find the variable declaration for 's' *) let items = tu.desc.items in let s_decl = List.find_opt (fun d -> match d.Clang.Ast.desc with | Clang.Ast.Var { var_name = "s"; _ } -> true | _ -> false) items in match s_decl with | Some node -> let ty = Clang.Type.of_node node in let size = Clang.Type.get_size_of ty in (* size in bits *) let align = Clang.Type.get_align_of ty in (* alignment in bits *) Printf.printf "sizeof(S) = %Ld bits, alignof(S) = %Ld bits\n" size align; (* List struct fields *) let fields = Clang.Type.list_of_fields ty in List.iter (fun f -> match f.Clang.Ast.desc with | Clang.Ast.Field { name; qual_type; _ } -> Printf.printf " field %s : %s\n" name (Clang.Type.show (Clang.Type.of_node f)) | _ -> ()) fields | None -> () ``` -------------------------------- ### Get Enum Constant Values with ClangML Source: https://context7.com/ocamllibs/clangml/llms.txt Retrieve the computed integer value of an enum constant. This function is useful for working with enumerated types in C/C++ code. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "enum color { RED, GREEN = 5, BLUE };" let () = match tu.desc.items with | [{ desc = Clang.Ast.EnumDecl { name = "color"; constants; _ }}] -> List.iter (fun c -> let v = Clang.Enum_constant.get_value c in Printf.printf "%s = %d\n" c.desc.constant_name v) constants | _ -> assert false (* Output: RED = 0 GREEN = 5 BLUE = 6 *) ``` -------------------------------- ### Control AST construction with Clang.Ast.Options Source: https://context7.com/ocamllibs/clangml/llms.txt Demonstrates how to configure AST construction options to retain implicit casts and parentheses for a more faithful representation of the source code. Verifies that an implicit cast is retained in the parsed AST. ```ocaml (* By default, implicit casts and parentheses are stripped. Disable both for a fully faithful AST. *) let opts = { Clang.Ast.Options.default with ignore_implicit_cast = false; ignore_paren = false; ignore_paren_in_types = false; ignore_implicit_constructors = false; ignore_implicit_methods = false; ignore_injected_class_names = false; ignore_indirect_fields = false; ignore_anonymous_fields = false; } let tu = Clang.Ast.parse_string ~options:opts ~filename:".c" "int i; i;" let () = match tu.desc.items with | [_; { desc = Clang.Ast.Function { body = Some { desc = Compound [ { desc = Expr { desc = Cast { kind = Implicit; qual_type = { desc = BuiltinType Int }; operand = { desc = DeclRef { name = IdentifierName "i" }}}}}] }}}] -> print_endline "Implicit cast retained" | _ -> () ``` -------------------------------- ### Clang.get_compiler_predefined_macros / Clang.get_compiler_include_directories Source: https://context7.com/ocamllibs/clangml/llms.txt Query the compiler frontend for its predefined macros and default include directories, useful for building compile commands that mirror the host compiler. ```APIDOC ## `Clang.get_compiler_predefined_macros` / `Clang.get_compiler_include_directories` — Compiler environment Query the compiler frontend for its predefined macros and default include directories, useful for building compile commands that mirror the host compiler. ```ocaml let () = (* Get macros predefined by clang (or gcc with ~compiler:"gcc") *) let macros = Clang.get_compiler_predefined_macros () in Printf.printf "Got %d predefined macros\n" (List.length macros); (* Get default include directories *) let inc_dirs = Clang.get_compiler_include_directories () in List.iter (fun d -> Printf.printf " -I%s\n" d) inc_dirs; (* Use them when parsing a file that needs stddef.h etc. *) let command_line_args = List.map Clang.Command_line.define macros @ List.map Clang.Command_line.include_directory inc_dirs @ [Clang.Command_line.include_directory Clang.includedir] in let tu = Clang.Ast.parse_file ~command_line_args "my_program.c" in assert (not (Clang.Ast.has_severity Clang.error tu)) ``` ``` -------------------------------- ### Query Compiler Environment with ClangML Source: https://context7.com/ocamllibs/clangml/llms.txt Query the compiler frontend for its predefined macros and default include directories. This information is crucial for constructing accurate compile commands. ```ocaml let () = (* Get macros predefined by clang (or gcc with ~compiler:"gcc") *) let macros = Clang.get_compiler_predefined_macros () in Printf.printf "Got %d predefined macros\n" (List.length macros); (* Get default include directories *) let inc_dirs = Clang.get_compiler_include_directories () in List.iter (fun d -> Printf.printf " -I%s\n" d) inc_dirs; (* Use them when parsing a file that needs stddef.h etc. *) let command_line_args = List.map Clang.Command_line.define macros @ List.map Clang.Command_line.include_directory inc_dirs @ [Clang.Command_line.include_directory Clang.includedir] in let tu = Clang.Ast.parse_file ~command_line_args "my_program.c" in assert (not (Clang.Ast.has_severity Clang.error tu)) ``` -------------------------------- ### Low-level Parsing with Clang.parse_file / Clang.parse_string Source: https://context7.com/ocamllibs/clangml/llms.txt Use low-level entry points to parse files or strings, returning a `cxtranslationunit`. This can be inspected via raw libclang bindings or converted to a high-level AST. ```ocaml (* Low-level parse and manual cursor traversal *) let tu = Clang.parse_file ~command_line_args:["-std=c11"] ~options:(Clang.default_editing_translation_unit_options ()) "foo.c" let () = (* Print all diagnostics *) Seq.iter (fun diag -> Format.eprintf "%a@." Clang.pp_diagnostic diag) (Clang.seq_of_diagnostics tu); if Clang.has_severity Clang.error tu then (Printf.eprintf "Parse error\n"; exit 1); (* Convert to high-level AST *) let ast = Clang.Ast.of_cxtranslationunit tu in Printf.printf "%d top-level declarations\n" (List.length ast.desc.items); (* Low-level cursor iteration *) let root = Clang.get_translation_unit_cursor tu in Clang.iter_children (fun child -> let kind = Clang.get_cursor_kind child in Printf.printf "cursor kind: %s\n" (Clang.get_cursor_kind_spelling kind)) root ``` -------------------------------- ### Clang.Command_line — Build compiler command-line arguments Source: https://context7.com/ocamllibs/clangml/llms.txt This module provides helpers to construct compiler command-line flags such as `-std=`, `-x`, `-D`, and `-I` for use with `command_line_args`. ```APIDOC ## `Clang.Command_line` — Build compiler command-line arguments Helper module to construct `-std=`, `-x`, `-D`, and `-I` flags as strings for use in `command_line_args`. ```ocaml open Clang.Command_line let args = [ language CXX; (* -x c++ *) standard Cxx17; (* -std=c++17 *) define (`Name "NDEBUG"); (* -DNDEBUG *) define (`NameValue ("VERSION", "42")); (* -DVERSION=42 *) include_directory "/usr/local/include";(* -I/usr/local/include *) ] let tu = Clang.Ast.parse_string ~filename:".cpp" ~command_line_args:args "#ifdef NDEBUG\nstatic_assert(VERSION == 42);\n#endif\n" let () = assert (not (Clang.Ast.has_severity Clang.error tu)) ``` ``` -------------------------------- ### Low-level `Clang.parse_file` / `Clang.parse_string` — Raw libclang translation units Source: https://context7.com/ocamllibs/clangml/llms.txt These low-level entry points return a `cxtranslationunit` that can be inspected via raw libclang bindings or converted to the high-level AST using `Clang.Ast.of_cxtranslationunit`. ```APIDOC ## Low-level `Clang.parse_file` / `Clang.parse_string` — Raw libclang translation units The low-level entry points return a `cxtranslationunit` which can be inspected via raw libclang bindings or converted to the high-level AST with `Clang.Ast.of_cxtranslationunit`. ```ocaml (* Low-level parse and manual cursor traversal *) let tu = Clang.parse_file ~command_line_args:["-std=c11"] ~options:(Clang.default_editing_translation_unit_options ()) "foo.c" let () = (* Print all diagnostics *) Seq.iter (fun diag -> Format.eprintf "%a@." Clang.pp_diagnostic diag) (Clang.seq_of_diagnostics tu); if Clang.has_severity Clang.error tu then (Printf.eprintf "Parse error\n"; exit 1); (* Convert to high-level AST *) let ast = Clang.Ast.of_cxtranslationunit tu in Printf.printf "%d top-level declarations\n" (List.length ast.desc.items); (* Low-level cursor iteration *) let root = Clang.get_translation_unit_cursor tu in Clang.iter_children (fun child -> let kind = Clang.get_cursor_kind child in Printf.printf "cursor kind: %s\n" (Clang.get_cursor_kind_spelling kind)) root ``` ``` -------------------------------- ### Build Compiler Command-Line Arguments with Clang.Command_line Source: https://context7.com/ocamllibs/clangml/llms.txt Construct compiler command-line flags like `-std=`, `-x`, `-D`, and `-I` using the `Clang.Command_line` module. These arguments are then used in `command_line_args` for parsing. ```ocaml open Clang.Command_line let args = [ language CXX; standard Cxx17; define (`Name "NDEBUG"); define (`NameValue ("VERSION", "42")); include_directory "/usr/local/include"; ] let tu = Clang.Ast.parse_string ~filename:".cpp" ~command_line_args:args "#ifdef NDEBUG\nstatic_assert(VERSION == 42);\n#endif\n" let () = assert (not (Clang.Ast.has_severity Clang.error tu)) ``` -------------------------------- ### AST Visitor Pattern with Refl.Visit Source: https://context7.com/ocamllibs/clangml/llms.txt Traverse the AST using the visitor pattern enabled by ClangML's reflexive AST types. Visitors intercept specific node types during recursive traversal to perform custom actions. ```ocaml (* Find all functions that contain a loop in their body *) let function_body_has_loop body = let module V : Refl.Visit.VisitorS with type 'a Applicative.t = bool = struct module Applicative = Traverse.Applicative.Exists let hook : type a. a Refl.refl -> (a -> bool) -> a -> bool = fun refl super x -> match refl with | Clang.Ast.Refl_stmt -> (match x.desc with | While _ | For _ | Do _ -> true | _ -> super x) | _ -> super x end in let module Visit = Refl.Visit.Make (V) in Visit.visit [%refl: Clang.Ast.stmt] [] body (* Collect names of all functions that contain at least one loop *) let functions_with_loop tu = tu.Clang.Ast.desc.items |> List.filter_map (fun decl -> match decl.Clang.Ast.desc with | Clang.Ast.Function { name = IdentifierName n; body = Some body; _ } when function_body_has_loop body -> Some n | _ -> None) let () = let tu = Clang.Ast.parse_string ~filename:".c" "void f(void){for(;;){}} void g(void){int x=1;}" in let names = functions_with_loop tu in List.iter (Printf.printf "loop in: %s\n") names (* Output: loop in: f *) ``` -------------------------------- ### Clang.Ast.parse_file Source: https://context7.com/ocamllibs/clangml/llms.txt Parses a file on disk and returns its translation unit as a pattern-matchable `Clang.Ast.translation_unit`. Optional arguments control include paths, compiler flags, and AST construction options. ```APIDOC ## `Clang.Ast.parse_file` — Parse a C/C++ file into a high-level AST Parses a file on disk and returns its translation unit as a pattern-matchable `Clang.Ast.translation_unit`. Optional arguments control include paths, compiler flags, and AST construction options. ### Method ```ocaml val parse_file : ?command_line_args:string list -> ?options:Clang.Ast.Options.t -> string -> Clang.Ast.translation_unit ``` ### Parameters - `command_line_args` (list of string, optional): Compiler flags to pass to Clang. - `options` (`Clang.Ast.Options.t`, optional): Options to control AST construction behavior. - `filename` (string): The path to the C/C++ file to parse. ### Request Example ```ocaml (* Parse a C file and extract all top-level function names *) let tu = Clang.Ast.parse_file ~command_line_args:["-I/usr/include"] "example.c" let () = (* Check there are no errors *) Format.eprintf "%a@." (Clang.Ast.format_diagnostics Clang.not_ignored_diagnostics) tu; assert (not (Clang.Ast.has_severity Clang.error tu)); (* Walk top-level declarations *) List.iter (fun decl -> match decl.Clang.Ast.desc with | Clang.Ast.Function { name = IdentifierName fn_name; body = Some _; _ } -> Printf.printf "Found function: %s\n" fn_name | _ -> ()) tu.desc.items (* Example output: Found function: main Found function: helper *) ``` ### Response - `translation_unit` (`Clang.Ast.translation_unit`): The parsed translation unit representing the C/C++ file. ``` -------------------------------- ### Find Declaration Site and Compare Cursors with ClangML Source: https://context7.com/ocamllibs/clangml/llms.txt Resolve an expression's declaration site cursor and compare cursors for identity or ordering. This is useful for checking if two references point to the same declaration. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "{ int i; i; } { int i; i; }" (* Using pattern matching with Pattern library *) let () = let stmts = (* assume we have two compound statements *) [] in (* Example: check two DeclRef nodes point to different declarations *) ignore stmts; let tu2 = Clang.Ast.parse_string ~filename:".c" "int x; int* p = &x;" in let items = tu2.desc.items in match items with | [_; { desc = Clang.Ast.Var { var_init = Some { desc = UnaryOperator { kind = AddrOf; operand = ({ desc = DeclRef _ } as ref_expr) }};_ }}] -> let def_cursor = Clang.Expr.get_definition ref_expr in let null = Clang.get_null_cursor () in assert (not (Clang.equal_cursors def_cursor null)); Printf.printf "hash=%d\n" (Clang.hash_cursor def_cursor) | _ -> () ``` -------------------------------- ### Clang.Ast.Options Source: https://context7.com/ocamllibs/clangml/llms.txt The `Clang.Ast.Options.t` record carries flags that change which nodes appear in the returned AST (e.g., whether implicit casts, parentheses, or implicit constructors are preserved). ```APIDOC ## `Clang.Ast.Options` — Control AST construction behavior The `Clang.Ast.Options.t` record carries flags that change which nodes appear in the returned AST (e.g., whether implicit casts, parentheses, or implicit constructors are preserved). ### Record Fields - `ignore_implicit_cast` (bool): If true, implicit casts are ignored. - `ignore_paren` (bool): If true, parentheses are ignored. - `ignore_paren_in_types` (bool): If true, parentheses in type expressions are ignored. - `ignore_implicit_constructors` (bool): If true, implicit constructors are ignored. - `ignore_implicit_methods` (bool): If true, implicit methods are ignored. - `ignore_injected_class_names` (bool): If true, injected class names are ignored. - `ignore_indirect_fields` (bool): If true, indirect fields are ignored. - `ignore_anonymous_fields` (bool): If true, anonymous fields are ignored. ### Default Value `Clang.Ast.Options.default` provides the default set of options. ### Request Example ```ocaml (* By default, implicit casts and parentheses are stripped. Disable both for a fully faithful AST. *) let opts = { Clang.Ast.Options.default with ignore_implicit_cast = false; ignore_paren = false; ignore_paren_in_types = false; ignore_implicit_constructors = false; ignore_implicit_methods = false; ignore_injected_class_names = false; ignore_indirect_fields = false; ignore_anonymous_fields = false; } let tu = Clang.Ast.parse_string ~options:opts ~filename:".c" "int i; i;" let () = match tu.desc.items with | [_; { desc = Clang.Ast.Function { body = Some { desc = Compound [ { desc = Expr { desc = Cast { kind = Implicit; qual_type = { desc = BuiltinType Int }; operand = { desc = DeclRef { name = IdentifierName "i" }}}}}] }}}] -> print_endline "Implicit cast retained" | _ -> () ``` ``` -------------------------------- ### Clang.Expr.get_definition / Clang.compare_cursors Source: https://context7.com/ocamllibs/clangml/llms.txt Resolve an expression's declaration site cursor and compare cursors for identity or ordering. ```APIDOC ## `Clang.Expr.get_definition` / `Clang.compare_cursors` — Declaration site lookup Resolve an expression's declaration site cursor and compare cursors for identity or ordering. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "{ int i; i; } { int i; i; }" (* Using pattern matching with Pattern library *) let () = let stmts = (* assume we have two compound statements *) [] in (* Example: check two DeclRef nodes point to different declarations *) ignore stmts; let tu2 = Clang.Ast.parse_string ~filename:".c" "int x; int* p = &x;" in let items = tu2.desc.items in match items with | [_; { desc = Clang.Ast.Var { var_init = Some { desc = UnaryOperator { kind = AddrOf; operand = ({ desc = DeclRef _ } as ref_expr) }};_ }}] -> let def_cursor = Clang.Expr.get_definition ref_expr in let null = Clang.get_null_cursor () in assert (not (Clang.equal_cursors def_cursor null)); Printf.printf "hash=%d\n" (Clang.hash_cursor def_cursor) | _ -> () ``` ``` -------------------------------- ### Parse C file and extract function names using Clang.Ast.parse_file Source: https://context7.com/ocamllibs/clangml/llms.txt Parses a C file into a translation unit and iterates through top-level declarations to find function names. Ensures no errors occurred during parsing. ```ocaml (* Parse a C file and extract all top-level function names *) let tu = Clang.Ast.parse_file ~command_line_args:["-I/usr/include"] "example.c" let () = (* Check there are no errors *) Format.eprintf "%a@." (Clang.Ast.format_diagnostics Clang.not_ignored_diagnostics) tu; assert (not (Clang.Ast.has_severity Clang.error tu)); (* Walk top-level declarations *) List.iter (fun decl -> match decl.Clang.Ast.desc with | Clang.Ast.Function { name = IdentifierName fn_name; body = Some _; _ } -> Printf.printf "Found function: %s\n" fn_name | _ -> ()) tu.desc.items (* Example output: Found function: main Found function: helper *) ``` -------------------------------- ### AST Visitor pattern with Refl.Visit — Traversing the AST Source: https://context7.com/ocamllibs/clangml/llms.txt ClangML's AST types are reflexive, enabling generic visitors that intercept specific node types during recursive traversal. ```APIDOC ## AST Visitor pattern with `Refl.Visit` — Traversing the AST clangml's AST types are reflexive (derived with `refl`), enabling generic visitors. Visitors intercept specific node types during recursive traversal. ```ocaml (* Find all functions that contain a loop in their body *) let function_body_has_loop body = let module V : Refl.Visit.VisitorS with type 'a Applicative.t = bool = struct module Applicative = Traverse.Applicative.Exists let hook : type a. a Refl.refl -> (a -> bool) -> a -> bool = fun refl super x -> match refl with | Clang.Ast.Refl_stmt -> (match x.desc with | While _ | For _ | Do _ -> true | _ -> super x) | _ -> super x end in let module Visit = Refl.Visit.Make (V) in Visit.visit [%refl: Clang.Ast.stmt] [] body (* Collect names of all functions that contain at least one loop *) let functions_with_loop tu = tu.Clang.Ast.desc.items |> List.filter_map (fun decl -> match decl.Clang.Ast.desc with | Clang.Ast.Function { name = IdentifierName n; body = Some body; _ } when function_body_has_loop body -> Some n | _ -> None) let () = let tu = Clang.Ast.parse_string ~filename:".c" "void f(void){for(;;){}} void g(void){int x=1;}" in let names = functions_with_loop tu in List.iter (Printf.printf "loop in: %s\n") names (* Output: loop in: f *) ``` ``` -------------------------------- ### Parse C string and pattern-match AST with Clang.Ast.parse_string Source: https://context7.com/ocamllibs/clangml/llms.txt Parses a C string into a translation unit and performs pattern matching to verify the structure of the parsed AST, specifically for a simple addition function. ```ocaml (* Parse a C string and pattern-match on the resulting AST *) let tu = Clang.Ast.parse_string ~filename:".c" ~command_line_args:[] "int add(int x, int y) { return x + y; }" let () = let items = tu.desc.items in match items with | [{ desc = Function { name = IdentifierName "add"; function_type = { result = { desc = BuiltinType Int }; parameters = Some { non_variadic = [ { desc = { name = "x"; qual_type = { desc = BuiltinType Int } }}; { desc = { name = "y"; qual_type = { desc = BuiltinType Int } }} ]; variadic = false }} ; body = Some { desc = Compound [ { desc = Return (Some { desc = BinaryOperator { lhs = { desc = DeclRef { name = IdentifierName "x" }}; kind = Add; rhs = { desc = DeclRef { name = IdentifierName "y" }}}})}] }}] -> print_endline "Matched add(int x, int y) { return x + y; }" | _ -> assert false (* Parsing C++ with a standard flag *) let tu_cxx = Clang.Ast.parse_string ~filename:".cpp" ~command_line_args:[Clang.Command_line.standard Cxx17] "auto f() { return 42; }" ``` -------------------------------- ### Parse C++ String and Annotate Field Access Specifiers Source: https://context7.com/ocamllibs/clangml/llms.txt Parses a C++ string containing a class definition and iterates through its fields to print their access specifiers. Requires the ClangML library. ```ocaml let tu = Clang.Ast.parse_string ~filename:".cpp" "class C { int x; public: float y; protected: bool z; };" let () = match tu.desc.items with | [{ desc = Clang.Ast.RecordDecl { keyword = Class; name = "C"; _ } as decl_node }] -> let cursor = Clang.Ast.cursor_of_node (Clang.Ast.node (Clang.Ast.Custom(Clang.Ast.IdNode).Cursor (Clang.get_null_cursor ()))) in (* Use the raw cursor approach *) ignore cursor; (* The high-level way: check CXXAccessSpecifier nodes in fields *) (match decl_node with | RecordDecl { fields; _ } -> List.iter (fun f -> match f.Clang.Ast.desc with | Clang.Ast.AccessSpecifier spec -> Printf.printf "access: %s\n" (Clang.string_of_cxx_access_specifier spec) | Clang.Ast.Field { name; _ } -> Printf.printf " field: %s\n" name | _ -> ()) fields | _ -> ()) | _ -> () ``` -------------------------------- ### Clang.Lazy.Ast — Lazy AST for large translation units Source: https://context7.com/ocamllibs/clangml/llms.txt The lazy AST variant mirrors the eager API but wraps every `desc` field in `Lazy.t`. This computes subtrees only when forced, avoiding upfront conversion of the full AST when only a small portion is needed. ```APIDOC ## `Clang.Lazy.Ast` — Lazy AST for large translation units The lazy variant mirrors the eager API but wraps every `desc` field in `Lazy.t`, computing subtrees only when forced. This avoids converting the full AST upfront when only a small portion is needed. ```ocaml (* Use the lazy AST to inspect only the top-level names without converting every nested node *) let tu_lazy : Clang.Ast.translation_unit = Clang.Lazy.Ast.parse_file "large_project.c" |> Clang.Ast.of_cxtranslationunit (* lazy variant stores Lazy.t descs *) (* Alternatively, parse eagerly but use Clang.Lazy.Ast.of_cxtranslationunit *) let tu_raw = Clang.parse_file "large_project.c" ~options:(Clang.default_editing_translation_unit_options ())) let lazy_tu = Clang.Lazy.Ast.of_cxtranslationunit tu_raw let () = (* desc is a lazy value; forcing only what we need *) let items = (Lazy.force lazy_tu.desc).items in List.iter (fun decl -> match Lazy.force decl.Clang.Lazy.Ast.desc with | Clang.Lazy.Ast.Function { name = IdentifierName n; _ } -> Printf.printf "function: %s\n" n | _ -> ()) items ``` ``` -------------------------------- ### Clang.Type.of_node / Clang.Type.get_size_of / Clang.Type.get_align_of Source: https://context7.com/ocamllibs/clangml/llms.txt Retrieve and query the type associated with any AST node, including its size and alignment in bits. ```APIDOC ## `Clang.Type.of_node` / `Clang.Type.get_size_of` / `Clang.Type.get_align_of` — Type information Retrieve and query the type associated with any AST node, including its size and alignment. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "struct S { int a; double b; }; struct S s;" let () = (* Find the variable declaration for 's' *) let items = tu.desc.items in let s_decl = List.find_opt (fun d -> match d.Clang.Ast.desc with | Clang.Ast.Var { var_name = "s"; _ } -> true | _ -> false) items in match s_decl with | Some node -> let ty = Clang.Type.of_node node in let size = Clang.Type.get_size_of ty in (* size in bits *) let align = Clang.Type.get_align_of ty in (* alignment in bits *) Printf.printf "sizeof(S) = %Ld bits, alignof(S) = %Ld bits\n" size align; (* List struct fields *) let fields = Clang.Type.list_of_fields ty in List.iter (fun f -> match f.Clang.Ast.desc with | Clang.Ast.Field { name; qual_type; _ } -> Printf.printf " field %s : %s\n" name (Clang.Type.show (Clang.Type.of_node f)) | _ -> ()) fields | None -> () ``` ``` -------------------------------- ### Lazy AST Parsing with Clang.Lazy.Ast Source: https://context7.com/ocamllibs/clangml/llms.txt Use the lazy AST variant to inspect only top-level names without converting the entire AST upfront. This is beneficial for large translation units where only a small portion of the AST is needed. ```ocaml (* Use the lazy AST to inspect only the top-level names without converting every nested node *) let tu_lazy : Clang.Ast.translation_unit = Clang.Lazy.Ast.parse_file "large_project.c" |> Clang.Ast.of_cxtranslationunit (* lazy variant stores Lazy.t descs *) (* Alternatively, parse eagerly but use Clang.Lazy.Ast.of_cxtranslationunit *) let tu_raw = Clang.parse_file "large_project.c" ~options:(Clang.default_editing_translation_unit_options ()) let lazy_tu = Clang.Lazy.Ast.of_cxtranslationunit tu_raw let () = (* desc is a lazy value; forcing only what we need *) let items = (Lazy.force lazy_tu.desc).items in List.iter (fun decl -> match Lazy.force decl.Clang.Lazy.Ast.desc with | Clang.Lazy.Ast.Function { name = IdentifierName n; _ } -> Printf.printf "function: %s\n" n | _ -> ()) items ``` -------------------------------- ### Clang.Ast.parse_string Source: https://context7.com/ocamllibs/clangml/llms.txt Parses an in-memory string as a translation unit, optionally specifying a virtual filename and compiler flags. Use a `.cpp` filename to parse C++ source. ```APIDOC ## `Clang.Ast.parse_string` — Parse a C/C++ snippet from a string Parses an in-memory string as a translation unit, optionally specifying a virtual filename and compiler flags. Use a `.cpp` filename to parse C++ source. ### Method ```ocaml val parse_string : ?filename:string -> ?command_line_args:string list -> ?options:Clang.Ast.Options.t -> string -> Clang.Ast.translation_unit ``` ### Parameters - `filename` (string, optional): A virtual filename to associate with the string, useful for determining language (e.g., `.c` or `.cpp`). Defaults to `.c`. - `command_line_args` (list of string, optional): Compiler flags to pass to Clang. - `options` (`Clang.Ast.Options.t`, optional): Options to control AST construction behavior. - `source_code` (string): The C/C++ code snippet to parse. ### Request Example ```ocaml (* Parse a C string and pattern-match on the resulting AST *) let tu = Clang.Ast.parse_string ~filename:".c" ~command_line_args:[] "int add(int x, int y) { return x + y; }" let () = let items = tu.desc.items in match items with | [{ desc = Function { name = IdentifierName "add"; function_type = { result = { desc = BuiltinType Int }; parameters = Some { non_variadic = [ { desc = { name = "x"; qual_type = { desc = BuiltinType Int } }}; { desc = { name = "y"; qual_type = { desc = BuiltinType Int } }} ]; variadic = false } }; body = Some { desc = Compound [ { desc = Return (Some { desc = BinaryOperator { lhs = { desc = DeclRef { name = IdentifierName "x" }}; kind = Add; rhs = { desc = DeclRef { name = IdentifierName "y" }}}})}] }}] | _ -> assert false (* Parsing C++ with a standard flag *) let tu_cxx = Clang.Ast.parse_string ~filename:".cpp" ~command_line_args:[Clang.Command_line.standard Cxx17] "auto f() { return 42; }" ``` ### Response - `translation_unit` (`Clang.Ast.translation_unit`): The parsed translation unit representing the C/C++ code snippet. ``` -------------------------------- ### Resolve Typedef Chains with ClangML Source: https://context7.com/ocamllibs/clangml/llms.txt Unwrap typedefs to find the underlying concrete type. Use the `recursive` option to resolve the entire chain of typedefs. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "typedef int my_int; typedef my_int wrapped_int; wrapped_int x;" let () = let items = tu.desc.items in let x_node = List.find (fun d -> match d.Clang.Ast.desc with | Clang.Ast.Var { var_name = "x"; _ } -> true | _ -> false) items in let ty = Clang.Type.of_node x_node in (* Single step: my_int *) let one_step = Clang.Type.get_typedef_underlying_type ty in Printf.printf "one step: %s\n" (Clang.Type.show one_step); (* Recursive: int *) let base = Clang.Type.get_typedef_underlying_type ~recursive:true ty in Printf.printf "base type: %s\n" (Clang.Type.show base) (* Output: one step: my_int base type: int *) ``` -------------------------------- ### Clang.Type.get_typedef_underlying_type Source: https://context7.com/ocamllibs/clangml/llms.txt Unwrap one or more levels of typedef to reach the underlying concrete type. ```APIDOC ## `Clang.Type.get_typedef_underlying_type` — Resolve typedef chains Unwrap one or more levels of typedef to reach the underlying concrete type. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "typedef int my_int; typedef my_int wrapped_int; wrapped_int x;" let () = let items = tu.desc.items in let x_node = List.find (fun d -> match d.Clang.Ast.desc with | Clang.Ast.Var { var_name = "x"; _ } -> true | _ -> false) items in let ty = Clang.Type.of_node x_node in (* Single step: my_int *) let one_step = Clang.Type.get_typedef_underlying_type ty in Printf.printf "one step: %s\n" (Clang.Type.show one_step); (* Recursive: int *) let base = Clang.Type.get_typedef_underlying_type ~recursive:true ty in Printf.printf "base type: %s\n" (Clang.Type.show base) (* Output: one step: my_int base type: int *) ``` ``` -------------------------------- ### Clang.Enum_constant.get_value Source: https://context7.com/ocamllibs/clangml/llms.txt Retrieve the computed integer value of an enum constant. ```APIDOC ## `Clang.Enum_constant.get_value` — Enum constant integer values Retrieve the computed integer value of an enum constant. ```ocaml let tu = Clang.Ast.parse_string ~filename:".c" "enum color { RED, GREEN = 5, BLUE };" let () = match tu.desc.items with | [{ desc = Clang.Ast.EnumDecl { name = "color"; constants; _ }}] -> List.iter (fun c -> let v = Clang.Enum_constant.get_value c in Printf.printf "%s = %d\n" c.desc.constant_name v) constants | _ -> assert false (* Output: RED = 0 GREEN = 5 BLUE = 6 *) ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.