variant_config/dsl/
mod.rs1pub mod fn_translator;
2mod frontend;
3mod utils;
4mod variant_value;
5
6use ahash::RandomState;
7use anyhow;
8use cranelift::prelude::*;
9use cranelift_jit::{JITBuilder, JITModule};
10use cranelift_module::{Linkage, Module};
11use fn_translator::*;
12use frontend::*;
13use hashbrown::HashMap;
14use std::mem;
15pub use variant_value::*;
16
17const N_PARAMS: usize = 20;
18pub type FnSignature = fn(
20 i64,
21 i64,
22 i64,
23 i64,
24 i64,
25 i64,
26 i64,
27 i64,
28 i64,
29 i64,
30 i64,
31 i64,
32 i64,
33 i64,
34 i64,
35 i64,
36 i64,
37 i64,
38 i64,
39 i64,
40) -> bool;
41pub const BOOL: Type = types::B1;
42pub const INT: Type = types::I64;
43
44pub struct FnJitter {
45 module: JITModule,
46 random_state: RandomState,
47 params: HashMap<String, Variable>,
48 pub func: FnSignature,
49}
50
51impl FnJitter {
52 pub fn new(input: &str) -> anyhow::Result<Self> {
53 let builder = JITBuilder::new(cranelift_module::default_libcall_names());
54 let mut module = JITModule::new(builder);
55 let mut ctx = module.make_context();
56 let random_state = RandomState::new();
57 let mut params = HashMap::with_capacity(N_PARAMS);
58 let fn_ptr = Self::compile(input, &mut module, &mut ctx, &random_state, &mut params)
59 .map_err(|e| {
60 anyhow::anyhow!(format!("Unable to parse condition `{}` :{}", input, e))
61 })?;
62 Ok(Self {
63 module,
64 random_state,
65 params,
66 func: unsafe { mem::transmute::<_, FnSignature>(fn_ptr) },
67 })
68 }
69
70 pub fn evaluate(&self, params: &HashMap<String, VariantValue>) -> bool {
71 let mut a: [i64; N_PARAMS] = [0; N_PARAMS];
72 for (k, idx) in &self.params {
73 if let Some(v) = params.get(k) {
74 a[idx.index()] = v.to_i64(&self.random_state);
75 }
76 }
77
78 (self.func)(
79 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13],
80 a[14], a[15], a[16], a[17], a[18], a[19],
81 )
82 }
83
84 fn compile(
85 input: &str,
86 module: &mut JITModule,
87 ctx: &mut codegen::Context,
88 random_state: &RandomState,
89 params: &mut HashMap<String, Variable>,
90 ) -> anyhow::Result<*const u8> {
91 let stmts = parser::statements(input).map_err(|e| e)?;
92 for _ in 0..N_PARAMS {
93 ctx.func.signature.params.push(AbiParam::new(INT));
94 }
95 ctx.func.signature.returns.push(AbiParam::new(BOOL));
96
97 let mut builder_context = FunctionBuilderContext::new();
98 let mut builder = FunctionBuilder::new(&mut ctx.func, &mut builder_context);
99
100 let entry_block = builder.create_block();
101 builder.append_block_params_for_function_params(entry_block);
102 builder.switch_to_block(entry_block);
103 builder.seal_block(entry_block);
104
105 let mut return_value = ValueWrapper::new(builder.ins().bconst(BOOL, false), BOOL);
106 let mut trans = FunctionTranslator::new(random_state, &mut builder, params, entry_block);
107 for expr in stmts {
108 return_value = trans.translate_expr(expr)?;
109 }
110 return_value = trans.convert_int_to_bool(return_value);
111 trans.return_and_finalize(return_value.value);
112
113 let id = module
114 .declare_function("fn", Linkage::Export, &ctx.func.signature)
115 .map_err(|e| e)?;
116 module
117 .define_function(
118 id,
119 ctx,
120 &mut codegen::binemit::NullTrapSink {},
121 &mut codegen::binemit::NullStackMapSink {},
122 )
123 .map_err(|e| e)?;
124 module.clear_context(ctx);
125 module.finalize_definitions();
126 let code = module.get_finalized_function(id);
127 Ok(code)
128 }
129
130 pub(crate) unsafe fn free_memory(self) {
131 self.module.free_memory();
132 }
133}