customasm/expr/
builtin_fn.rs

1use crate::*;
2
3
4pub fn resolve_builtin_fn(
5    name: &str)
6    -> Option<fn(&mut expr::EvalFunctionQuery) -> Result<expr::Value, ()>>
7{
8    match name.as_ref()
9    {
10        "assert" => Some(eval_builtin_assert),
11        "sizeof" => Some(eval_builtin_sizeof),
12        "le" => Some(eval_builtin_le),
13        "ascii" => Some(eval_builtin_ascii),
14        "utf8" => Some(eval_builtin_utf8),
15        "utf16be" => Some(eval_builtin_utf16be),
16        "utf16le" => Some(eval_builtin_utf16le),
17        "utf32be" => Some(eval_builtin_utf32be),
18        "utf32le" => Some(eval_builtin_utf32le),
19        "strlen" => Some(eval_builtin_strlen),
20        _ => None,
21    }
22}
23
24
25pub fn get_static_size_builtin_fn(
26    name: &str,
27    provider: &expr::StaticallyKnownProvider,
28    args: &Vec<expr::Expr>)
29    -> Option<usize>
30{
31    let get_static_size_fn = {
32        match name.as_ref()
33        {
34            "sizeof" => get_static_size_builtin_sizeof,
35            "le" => get_static_size_builtin_le,
36            _ => return None,
37        }
38    };
39
40    get_static_size_fn(
41        provider,
42        args)
43}
44
45
46pub fn get_statically_known_value_builtin_fn(
47    name: &str,
48    _args: &Vec<expr::Expr>)
49    -> bool
50{
51    match name.as_ref()
52    {
53        "assert" => false,
54        "sizeof" => true,
55        "le" => true,
56        "ascii" => true,
57        "utf8" => true,
58        "utf16be" => true,
59        "utf16le" => true,
60        "utf32be" => true,
61        "utf32le" => true,
62        "strlen" => true,
63        _ => false,
64    }
65}
66
67
68pub fn eval_builtin_fn(
69    query: &mut expr::EvalFunctionQuery)
70    -> Result<expr::Value, ()>
71{
72    let builtin_name = {
73        match query.func
74        {
75            expr::Value::ExprBuiltInFunction(ref name) => name,
76            _ => unreachable!(),
77        }
78    };
79
80    let builtin_fn = resolve_builtin_fn(builtin_name).unwrap();
81    builtin_fn(query)
82}
83
84
85pub fn eval_builtin_assert(
86    query: &mut expr::EvalFunctionQuery)
87    -> Result<expr::Value, ()>
88{
89    query.ensure_min_max_arg_number(1, 2)?;
90
91    let condition = query.args[0]
92        .value
93        .expect_bool(
94            query.report,
95            query.args[0].span)?;
96
97    if !condition
98    {
99        let msg = {
100            if query.args.len() == 2
101            {
102                diagn::Message::error_span(
103                    format!(
104                        "assertion failed: {}",
105                        query.args[1]
106                            .value
107                            .expect_string(query.report, query.args[1].span)?
108                            .utf8_contents),
109                    query.span)
110            }
111            else {
112                diagn::Message::error_span("assertion failed", query.span)
113            }
114        };
115        
116        return Ok(expr::Value::FailedConstraint(
117            query.report.wrap_in_parents_capped(msg)));
118    }
119
120    Ok(expr::Value::Void)
121}
122
123
124pub fn eval_builtin_sizeof(
125    query: &mut expr::EvalFunctionQuery)
126    -> Result<expr::Value, ()>
127{
128    query.ensure_arg_number(1)?;
129
130    let (_bigint, size) = query.args[0].value.expect_sized_integerlike(
131        query.report,
132        query.args[0].span)?;
133    
134    Ok(expr::Value::make_integer(size))
135}
136
137
138pub fn eval_builtin_le(
139    query: &mut expr::EvalFunctionQuery)
140    -> Result<expr::Value, ()>
141{
142    query.ensure_arg_number(1)?;
143
144    let bigint = query.args[0].value.expect_sized_bigint(
145        query.report,
146        query.args[0].span)?;
147    
148    if bigint.size.unwrap() % 8 != 0
149    {
150        query.report.push_parent(
151            "argument to `le` must have a size multiple of 8",
152            query.args[0].span);
153
154        query.report.note(format!(
155            "got size {}",
156            bigint.size.unwrap()));
157
158        query.report.pop_parent();
159        
160        return Err(());
161    }
162
163    Ok(expr::Value::make_integer(bigint.convert_le()))
164}
165
166
167pub fn get_static_size_builtin_sizeof(
168    provider: &expr::StaticallyKnownProvider,
169    args: &Vec<expr::Expr>)
170    -> Option<usize>
171{
172    if args.len() == 1
173    {
174        args[0].get_static_size(provider)
175    }
176    else
177    {
178        None
179    }
180}
181
182
183pub fn get_static_size_builtin_le(
184    provider: &expr::StaticallyKnownProvider,
185    args: &Vec<expr::Expr>)
186    -> Option<usize>
187{
188    if args.len() == 1
189    {
190        args[0].get_static_size(provider)
191    }
192    else
193    {
194        None
195    }
196}
197
198
199pub fn eval_builtin_string_encoding(
200    encoding: &str,
201    query: &mut expr::EvalFunctionQuery)
202    -> Result<expr::Value, ()>
203{
204    query.ensure_arg_number(1)?;
205
206    let s = query.args[0].value.expect_string(
207        query.report,
208        query.args[0].span)?;
209
210    Ok(expr::Value::make_string(
211        &s.utf8_contents,
212        encoding))
213}
214
215
216pub fn eval_builtin_ascii(
217    query: &mut expr::EvalFunctionQuery)
218    -> Result<expr::Value, ()>
219{
220    eval_builtin_string_encoding("ascii", query)
221}
222
223
224pub fn eval_builtin_utf8(
225    query: &mut expr::EvalFunctionQuery)
226    -> Result<expr::Value, ()>
227{
228    eval_builtin_string_encoding("utf8", query)
229}
230
231
232pub fn eval_builtin_utf16be(
233    query: &mut expr::EvalFunctionQuery)
234    -> Result<expr::Value, ()>
235{
236    eval_builtin_string_encoding("utf16be", query)
237}
238
239
240pub fn eval_builtin_utf16le(
241    query: &mut expr::EvalFunctionQuery)
242    -> Result<expr::Value, ()>
243{
244    eval_builtin_string_encoding("utf16le", query)
245}
246
247
248pub fn eval_builtin_utf32be(
249    query: &mut expr::EvalFunctionQuery)
250    -> Result<expr::Value, ()>
251{
252    eval_builtin_string_encoding("utf32be", query)
253}
254
255
256pub fn eval_builtin_utf32le(
257    query: &mut expr::EvalFunctionQuery)
258    -> Result<expr::Value, ()>
259{
260    eval_builtin_string_encoding("utf32le", query)
261}
262
263
264pub fn eval_builtin_strlen(
265    query: &mut expr::EvalFunctionQuery)
266    -> Result<expr::Value, ()>
267{
268    query.ensure_arg_number(1)?;
269
270    let s = query.args[0].value.expect_string(
271        query.report,
272        query.args[0].span)?;
273
274    Ok(expr::Value::make_integer(s.utf8_contents.len()))
275
276}