1use crate::ir::{
2 function::parser::ParserContext,
3 module::name,
4 types::{self, Type, Types, I1, I32, I64, I8},
5 util::{spaces, string_literal},
6 value::{
7 ConstantArray, ConstantData, ConstantExpr, ConstantInt, ConstantStruct, Value, ValueId,
8 },
9};
10use nom::{
11 branch::alt,
12 bytes::complete::tag,
13 character::complete::{char, digit1},
14 combinator::{opt, recognize},
15 error::VerboseError,
16 sequence::{preceded, tuple},
17 IResult,
18};
19
20pub fn parse_constant<'a>(
21 source: &'a str,
22 types: &Types,
23 ty: Type,
24) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
25 if let Ok((source, _)) = preceded(spaces, tag("undef"))(source) {
26 return Ok((source, ConstantData::Undef));
27 }
28 if let Ok((source, _)) = preceded(spaces, tag("null"))(source) {
29 return Ok((source, ConstantData::Null));
30 }
31 if let Ok((source, _)) = preceded(spaces, tag("zeroinitializer"))(source) {
32 return Ok((source, ConstantData::AggregateZero));
33 }
34 if let Ok((source, id)) = parse_constant_int(source, ty) {
35 return Ok((source, id.into()));
36 }
37 if let Ok((source, id)) = parse_constant_array(source, types) {
38 return Ok((source, id));
39 }
40 if let Ok((source, id)) = parse_constant_global_ref(source) {
41 return Ok((source, id));
42 }
43 if let Ok((source, id)) = parse_constant_struct(source, types) {
44 return Ok((source, id));
45 }
46 parse_constant_expr(source, types)
47}
48
49pub fn parse_constant_int<'a>(
50 source: &'a str,
51 ty: Type,
52) -> IResult<&'a str, ConstantInt, VerboseError<&'a str>> {
53 let (source, num) = preceded(
54 spaces,
55 recognize(tuple((
56 opt(char('-')),
57 alt((digit1, tag("true"), tag("false"))),
58 ))),
59 )(source)?;
60 let val = match ty {
61 I1 => ConstantInt::Int1(num == "true"),
62 I8 => ConstantInt::Int8(num.parse::<i8>().unwrap()),
63 I32 => ConstantInt::Int32(num.parse::<i32>().unwrap()),
64 I64 => ConstantInt::Int64(num.parse::<i64>().unwrap()),
65 _ => todo!(),
66 };
67 Ok((source, val))
68}
69
70pub fn parse_constant_array<'a>(
71 source: &'a str,
72 _types: &Types,
73 ) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
75 let (source, _) = preceded(spaces, char('c'))(source)?;
77 let (source, s) = preceded(spaces, string_literal)(source)?;
78 let val = ConstantData::Array(ConstantArray {
79 elem_ty: I8,
80 elems: s
81 .as_bytes()
82 .iter()
83 .map(|c| ConstantData::Int(ConstantInt::Int8(*c as i8)))
84 .collect(),
85 is_string: true,
86 });
87 Ok((source, val))
88
89 }
104
105pub fn parse_constant_expr<'a>(
106 source: &'a str,
107 types: &Types,
108) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
109 if let Ok((source, konst)) = parse_constant_getelementptr(source, types) {
110 return Ok((source, konst));
111 }
112 parse_constant_bitcast(source, types)
113}
114
115pub fn parse_constant_getelementptr<'a>(
116 source: &'a str,
117 types: &Types,
118) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
119 let (source, _) = preceded(spaces, tag("getelementptr"))(source)?;
120 let (source, inbounds) = opt(preceded(spaces, tag("inbounds")))(source)?;
121 let (source, _) = preceded(spaces, char('('))(source)?;
122 let (source, ty) = types::parse(source, types)?;
123 let (mut source, _) = preceded(spaces, char(','))(source)?;
124 let mut args = vec![];
125 let mut tys = vec![ty];
126 loop {
127 let (source_, ty) = types::parse(source, types)?;
128 let (source_, arg) = parse_constant(source_, types, ty)?;
129 tys.push(ty);
130 args.push(arg);
131 if let Ok((source_, _)) = preceded(spaces, char(','))(source_) {
132 source = source_;
133 continue;
134 }
135 if let Ok((source, _)) = preceded(spaces, char(')'))(source_) {
136 return Ok((
137 source,
138 ConstantData::Expr(ConstantExpr::GetElementPtr {
139 inbounds: inbounds.is_some(),
140 tys,
141 args,
142 }),
143 ));
144 }
145 }
146}
147
148pub fn parse_constant_bitcast<'a>(
149 source: &'a str,
150 types: &Types,
151) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
152 let (source, _) = preceded(spaces, tag("bitcast"))(source)?;
153 let (source, _) = preceded(spaces, char('('))(source)?;
154 let (source, from) = types::parse(source, types)?;
155 let (source, arg) = parse_constant(source, types, from)?;
156 let (source, _) = preceded(spaces, tag("to"))(source)?;
157 let (source, to) = types::parse(source, types)?;
158 let (source, _) = preceded(spaces, char(')'))(source)?;
159 Ok((
160 source,
161 ConstantData::Expr(ConstantExpr::Bitcast {
162 tys: [from, to],
163 arg: Box::new(arg),
164 }),
165 ))
166}
167
168pub fn parse_constant_global_ref(source: &str) -> IResult<&str, ConstantData, VerboseError<&str>> {
169 let (source, name) = preceded(spaces, preceded(char('@'), name::parse))(source)?;
170 Ok((source, ConstantData::GlobalRef(name)))
171}
172
173pub fn parse_constant_struct<'a>(
174 source: &'a str,
175 types: &Types,
176) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
177 let (mut source, is_packed) = preceded(spaces, alt((tag("{"), tag("<{"))))(source)?;
178 let is_packed = is_packed == "<{";
179 let mut elems = vec![];
180 let mut elems_ty = vec![];
181 loop {
182 let (source_, t) = types::parse(source, types)?;
183 let (source_, konst) = parse_constant(source_, types, t)?;
184 elems.push(konst);
185 elems_ty.push(t);
186 if let Ok((source_, _)) = preceded(spaces, char(','))(source_) {
187 source = source_;
188 continue;
189 }
190 let (source_, _) = preceded(spaces, tag(if is_packed { "}>" } else { "}" }))(source_)?;
191 return Ok((
192 source_,
193 ConstantData::Struct(ConstantStruct {
194 elems_ty,
195 elems,
196 is_packed,
197 }),
198 ));
199 }
200}
201
202pub fn parse_local<'a, 'b>(
203 source: &'a str,
204 ctx: &mut ParserContext<'b>,
205 _ty: Type,
206) -> IResult<&'a str, ValueId, VerboseError<&'a str>> {
207 let (source, name) = preceded(spaces, preceded(char('%'), name::parse))(source)?;
208 Ok((source, ctx.get_or_create_named_value(name)))
209}
210
211pub fn parse<'a, 'b>(
212 source: &'a str,
213 ctx: &mut ParserContext<'b>,
214 ty: Type,
215) -> IResult<&'a str, ValueId, VerboseError<&'a str>> {
216 if let Ok((source, konst)) = parse_constant(source, ctx.types, ty) {
217 let id = ctx.data.create_value(Value::Constant(konst));
218 return Ok((source, id));
219 }
220
221 parse_local(source, ctx, ty)
222}