-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclang_parser.rs
More file actions
78 lines (67 loc) · 2.51 KB
/
Copy pathclang_parser.rs
File metadata and controls
78 lines (67 loc) · 2.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Invokes Clang as the C++ frontend and converts its AST dump into a schema.
use crate::schema::Schema;
use std::fs;
use std::process::Command;
/// Options that must match the compilation environment of the parsed header.
#[derive(Debug, Clone)]
pub struct ClangOptions {
/// Clang-compatible frontend executable, such as `clang` or `clang++`.
pub executable: String,
/// Language standard without the `-std=` prefix.
pub standard: String,
/// Include paths, defines, target options, sysroot, and other project flags.
pub extra_args: Vec<String>,
}
impl Default for ClangOptions {
fn default() -> Self {
Self {
executable: "clang".to_string(),
standard: "c++20".to_string(),
extra_args: Vec::new(),
}
}
}
pub fn generate_clang_ast_dump(header_path: &str) -> Result<String, String> {
generate_clang_ast_dump_with_options(header_path, &ClangOptions::default())
}
/// Parses a header with Clang and returns the complete JSON AST dump.
pub fn generate_clang_ast_dump_with_options(
header_path: &str,
options: &ClangOptions,
) -> Result<String, String> {
let canonical = fs::canonicalize(header_path)
.map_err(|e| format!("Failed to read header {}: {}", header_path, e))?;
let mut command = Command::new(&options.executable);
command.args([
"-x",
"c++",
&format!("-std={}", options.standard),
"-fsyntax-only",
]);
// Project arguments precede the input so Clang applies them to the header.
command.args(&options.extra_args);
command.args(["-Xclang", "-ast-dump=json"]);
command.arg(&canonical);
let output = command
.output()
.map_err(|e| format!("Failed to invoke {}: {}", options.executable, e))?;
if !output.status.success() {
let err = String::from_utf8_lossy(&output.stderr);
return Err(format!("clang parse failed for {}: {}", header_path, err));
}
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}
pub fn parse_header_with_clang(header_path: &str) -> Result<Schema, String> {
parse_header_with_clang_options(header_path, &ClangOptions::default())
}
/// Parses a header and projects declarations owned by that header into a schema.
pub fn parse_header_with_clang_options(
header_path: &str,
options: &ClangOptions,
) -> Result<Schema, String> {
let ast_json = generate_clang_ast_dump_with_options(header_path, options)?;
Ok(Schema::parse_clang_ast_json_for_file(
&ast_json,
header_path,
))
}