Skip to main content

vicis_core/ir/value/
parser.rs

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    // ty: Type,
74) -> IResult<&'a str, ConstantData, VerboseError<&'a str>> {
75    // TODO: Support arrays in the form of [a, b, c]
76    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    // let (mut source, _) = preceded(spaces, char('['))(source)?;
90    // loop {
91    //     let (source_, ty) = types::parse(source, ctx.types)?;
92    //
93    // }
94
95    // let (source, num) = preceded(spaces, digit1)(source)?;
96    // let val = match &*ctx.types.get(ty) {
97    //     Type::Int(32) => Value::Constant(ConstantData::Int(ConstantInt::Int32(
98    //         num.parse::<i32>().unwrap(),
99    //     ))),
100    //     _ => todo!(),
101    // };
102    // Ok((source, ctx.data.create_value(val)))
103}
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}