1use super::super::function;
2use super::Module;
3use super::{
4 attributes::{parser::parse_attributes, Attribute},
5 global_variable, metadata, name,
6};
7use crate::ir::{
8 types,
9 util::{spaces, string_literal},
10};
11use nom;
12use nom::{
13 bytes::complete::tag,
14 character::complete::{char, digit1},
15 error::VerboseError,
16 sequence::{preceded, tuple},
17 IResult,
18};
19
20fn parse_source_filename(source: &str) -> IResult<&str, String, VerboseError<&str>> {
21 tuple((
22 tag("source_filename"),
23 preceded(spaces, char('=')),
24 preceded(spaces, string_literal),
25 ))(source)
26 .map(|(i, (_, _, name))| (i, name))
27}
28
29fn parse_target_datalayout(source: &str) -> IResult<&str, String, VerboseError<&str>> {
30 tuple((
31 tag("target"),
32 preceded(spaces, tag("datalayout")),
33 preceded(spaces, char('=')),
34 preceded(spaces, string_literal),
35 ))(source)
36 .map(|(i, (_, _, _, datalayout))| (i, datalayout))
37}
38
39fn parse_target_triple(source: &str) -> IResult<&str, String, VerboseError<&str>> {
40 tuple((
41 tag("target"),
42 preceded(spaces, tag("triple")),
43 preceded(spaces, char('=')),
44 preceded(spaces, string_literal),
45 ))(source)
46 .map(|(i, (_, _, _, triple))| (i, triple))
47}
48
49fn parse_attribute_group(source: &str) -> IResult<&str, (u32, Vec<Attribute>), VerboseError<&str>> {
50 tuple((
51 tag("attributes"),
52 preceded(spaces, char('#')),
53 digit1,
54 preceded(spaces, char('=')),
55 preceded(spaces, char('{')),
56 preceded(spaces, parse_attributes),
57 preceded(spaces, char('}')),
58 ))(source)
59 .map(|(i, (_, _, id, _, _, attrs, _))| (i, (id.parse().unwrap(), attrs)))
60}
61
62fn parse_local_type<'a>(
63 source: &'a str,
64 types: &types::Types,
65) -> IResult<&'a str, (), VerboseError<&'a str>> {
66 let (source, name) = preceded(spaces, preceded(char('%'), name::parse))(source)?;
67 types.base_mut().empty_named_type(name.clone()); let (source, _) = preceded(spaces, preceded(char('='), preceded(spaces, tag("type"))))(source)?;
69 let (source, ty) = types::parse(source, types)?;
70 types.base_mut().change_to_named_type(ty, name);
71 Ok((source, ()))
72}
73
74pub fn parse(mut source: &str) -> Result<Module, nom::Err<VerboseError<&str>>> {
75 let mut module = Module::new();
76 loop {
77 source = spaces(source)?.0;
78
79 if source.is_empty() {
80 break;
81 }
82
83 if let Ok((source_, source_filename)) = parse_source_filename(source) {
84 module.source_filename = source_filename;
85 source = source_;
86 continue;
87 }
88
89 if let Ok((source_, target_datalayout)) = parse_target_datalayout(source) {
90 module.target.datalayout = target_datalayout.to_string();
91 source = source_;
92 continue;
93 }
94
95 if let Ok((source_, target_triple)) = parse_target_triple(source) {
96 module.target.triple = target_triple.to_string();
97 source = source_;
98 continue;
99 }
100
101 if let Ok((source_, (id, attrs))) = parse_attribute_group(source) {
102 module.attributes.insert(id, attrs);
103 source = source_;
104 continue;
105 }
106
107 if let Ok((source_, _)) = parse_local_type(source, &module.types) {
108 source = source_;
109 continue;
110 }
111
112 if let Ok((source_, gv)) = global_variable::parse(source, &module.types) {
113 module.global_variables.insert(gv.name.clone(), gv);
114 source = source_;
115 continue;
116 }
117
118 if let Ok((source_, func)) = function::parse(source, module.types.clone()) {
119 module.functions.alloc(func);
120 source = source_;
121 continue;
122 }
123 if let Ok((source_, (name_, meta))) = metadata::parse(&module.types)(source) {
124 module.metas.insert(name_, meta);
125 source = source_;
126 continue;
127 }
128
129 todo!("unsupported syntax at {:?}", source)
130 }
131
132 Ok(module)
133}
134
135macro_rules! generate_test {
136 ($fname:ident, $name:literal) => {
137 #[test]
138 fn $fname() {
139 use nom::error::convert_error;
140 use std::fs;
141 let source = fs::read_to_string(concat!("./examples/", $name)).unwrap();
142 let module = match parse(&source) {
143 Ok(ok) => ok,
144 Err(nom::Err::Error(e)) => {
145 println!("{}", convert_error(source.as_str(), e));
146 panic!()
147 }
148 Err(e) => panic!("{:?}", e),
149 };
150 insta::assert_debug_snapshot!(module);
151 }
152 };
153}
154
155generate_test!(parse_example_addsubmul, "addsubmul.ll");
156generate_test!(parse_example_ary, "ary.ll");
157generate_test!(parse_example_br, "br.ll");
158generate_test!(parse_example_call, "call.ll");
159generate_test!(parse_example_cast, "cast.ll");
160generate_test!(parse_example_cgep, "cgep.ll");
161generate_test!(parse_example_dce, "dce.ll");
162generate_test!(parse_example_gblvar, "gblvar.ll");
163generate_test!(parse_example_icmp, "icmp.ll");
164generate_test!(parse_example_load, "load.ll");
165generate_test!(parse_example_loop, "loop.ll");
166generate_test!(parse_example_loop2, "loop2.ll");
167generate_test!(parse_example_manyargs, "manyargs.ll");
168generate_test!(parse_example_metadata, "metadata.ll");
169generate_test!(parse_example_node, "node.ll");
170generate_test!(parse_example_phi, "phi.ll");
171generate_test!(parse_example_phi_loop, "phi_loop.ll");
172generate_test!(parse_example_printf, "printf.ll");
173generate_test!(parse_example_puts, "puts.ll");
174generate_test!(parse_example_ret42, "ret42.ll");
175generate_test!(parse_example_rustc_fn_call, "rustc_fn_call.ll");
176generate_test!(parse_example_rustc_hello, "rustc_hello.ll");
177generate_test!(parse_example_rustc_minimum, "rustc_minimum.ll");
178generate_test!(parse_example_struct, "struct.ll");
179
180#[test]
181fn parse_module1() {
182 let result = parse(
183 r#"
184 source_filename = "c.c"
185 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
186 ; comments
187 ; bluh bluh
188 target triple = "x86_64-pc-linux-gnu" ; hogehoge
189 !0 = !{}
190 define dso_local i32 @main(i32 %0, i32 %1) #0 {
191 ret void
192 }
193 attributes #0 = { noinline "abcde" = ;fff
194 ;ff
195 "ff" "xxx"}
196 "#,
197 );
198 assert!(result.is_ok());
199 let result = result.unwrap();
200 assert_eq!(result.source_filename, "c.c");
201 assert_eq!(
202 result.target.datalayout,
203 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
204 );
205 assert_eq!(result.target.triple, "x86_64-pc-linux-gnu");
206 println!("{:?}", result);
207}
208
209#[test]
210#[rustfmt::skip]
211fn parse_module2() {
212 use rustc_hash::FxHashMap;
213 let result = parse(include_str!("../../../examples/ret42.ll"));
214 assert!(result.is_ok());
215 let result = result.unwrap();
216 assert_eq!(result.source_filename, "c.c");
217 assert_eq!(
218 result.target.datalayout,
219 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
220 );
221 assert_eq!(result.target.triple, "x86_64-pc-linux-gnu");
222 let attrs = vec![(
223 0u32,
224 vec![
225 Attribute::NoInline,
226 Attribute::NoUnwind,
227 Attribute::OptNone,
228 Attribute::UWTable,
229 Attribute::StringAttribute {kind: "correctly-rounded-divide-sqrt-fp-math".to_string(), value: "false" .to_string()},
230 Attribute::StringAttribute {kind: "disable-tail-calls" .to_string(), value: "false" .to_string()},
231 Attribute::StringAttribute {kind: "frame-pointer" .to_string(), value: "all" .to_string()},
232 Attribute::StringAttribute {kind: "less-precise-fpmad" .to_string(), value: "false" .to_string()},
233 Attribute::StringAttribute {kind: "min-legal-vector-width" .to_string(), value: "0" .to_string()},
234 Attribute::StringAttribute {kind: "no-infs-fp-math" .to_string(), value: "false" .to_string()},
235 Attribute::StringAttribute {kind: "no-jump-tables" .to_string(), value: "false" .to_string()},
236 Attribute::StringAttribute {kind: "no-nans-fp-math" .to_string(), value: "false" .to_string()},
237 Attribute::StringAttribute {kind: "no-signed-zeros-fp-math" .to_string(), value: "false" .to_string()},
238 Attribute::StringAttribute {kind: "no-trapping-math" .to_string(), value: "false" .to_string()},
239 Attribute::StringAttribute {kind: "stack-protector-buffer-size" .to_string(), value: "8" .to_string()},
240 Attribute::StringAttribute {kind: "target-cpu" .to_string(), value: "x86-64" .to_string()},
241 Attribute::StringAttribute {kind: "target-features" .to_string(), value: "+fxsr,+mmx,+sse,+sse2,+x87".to_string()},
242 Attribute::StringAttribute {kind: "unsafe-fp-math" .to_string(), value: "false" .to_string()},
243 Attribute::StringAttribute {kind: "use-soft-float" .to_string(), value: "false" .to_string()},
244 ],
245 )]
246 .into_iter()
247 .collect::<FxHashMap<u32, Vec<Attribute>>>();
248 for (key1, val1) in &result.attributes {
249 assert!(&attrs[key1] == val1)
250 }
251 println!("{:?}", result);
252}