1use crate::block::{BasicBlock, BlockId};
2use crate::contract::ModifierRef;
3use crate::types::Type;
4use cranelift::codegen::ir as clif_ir;
5use indexmap::IndexMap;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Function {
10 pub signature: FunctionSignature,
11 pub visibility: Visibility,
12 pub mutability: Mutability,
13 pub modifiers: Vec<ModifierRef>,
14 pub body: FunctionBody,
15 pub metadata: FunctionMetadata,
16}
17
18impl Function {
19 pub fn new(signature: FunctionSignature) -> Self {
20 Self {
21 signature,
22 visibility: Visibility::Private,
23 mutability: Mutability::NonPayable,
24 modifiers: Vec::new(),
25 body: FunctionBody::new(),
26 metadata: FunctionMetadata::default(),
27 }
28 }
29
30 pub fn name(&self) -> &str {
31 &self.signature.name
32 }
33
34 pub fn entry_block(&self) -> BlockId {
35 self.body.entry_block()
36 }
37
38 pub fn analyze_metadata(&mut self) {
39 let (calls_external, modifies_state) = self
40 .body
41 .blocks
42 .values()
43 .flat_map(|block| &block.instructions)
44 .fold((false, false), |(ext, state), inst| {
45 (
46 ext || inst.is_external_call(),
47 state || inst.is_state_changing(),
48 )
49 });
50
51 self.metadata.calls_external = calls_external;
52 self.metadata.modifies_state = modifies_state;
53 self.metadata.can_reenter = calls_external && modifies_state;
54 }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct FunctionSignature {
59 pub name: String,
60 pub params: Vec<Parameter>,
61 pub returns: Vec<Type>,
62 pub is_payable: bool,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct Parameter {
67 pub name: String,
68 pub param_type: Type,
69 pub location: DataLocation,
70}
71
72impl Parameter {
73 pub fn new(name: impl Into<String>, param_type: Type) -> Self {
74 Self {
75 name: name.into(),
76 param_type,
77 location: DataLocation::Memory,
78 }
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
83pub enum DataLocation {
84 Storage,
85 Memory,
86 Calldata,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
90pub enum Visibility {
91 Public,
92 External,
93 Internal,
94 Private,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
98pub enum Mutability {
99 Pure,
100 View,
101 NonPayable,
102 Payable,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct FunctionBody {
107 pub entry_block: BlockId,
108 pub blocks: IndexMap<BlockId, BasicBlock>,
109 pub locals: Vec<LocalVariable>,
110 #[serde(skip)]
111 pub cranelift_func: Option<CraneliftFunction>,
112 next_block_id: u32,
113 next_local_id: u32,
114}
115
116impl FunctionBody {
117 pub fn new() -> Self {
118 let entry_block = BlockId(0);
119 let mut blocks = IndexMap::new();
120 blocks.insert(entry_block, BasicBlock::new(entry_block));
121
122 Self {
123 entry_block,
124 blocks,
125 locals: Vec::new(),
126 cranelift_func: None,
127 next_block_id: 1,
128 next_local_id: 0,
129 }
130 }
131
132 pub fn create_block(&mut self) -> BlockId {
133 let id = BlockId(self.next_block_id);
134 self.next_block_id += 1;
135 self.blocks.insert(id, BasicBlock::new(id));
136 id
137 }
138
139 pub fn get_block(&self, id: BlockId) -> Option<&BasicBlock> {
140 self.blocks.get(&id)
141 }
142
143 pub fn get_block_mut(&mut self, id: BlockId) -> Option<&mut BasicBlock> {
144 self.blocks.get_mut(&id)
145 }
146
147 pub fn entry_block(&self) -> BlockId {
148 self.entry_block
149 }
150
151 pub fn add_local(&mut self, var: LocalVariable) -> LocalId {
152 let id = LocalId(self.next_local_id);
153 self.next_local_id += 1;
154 self.locals.push(var);
155 id
156 }
157}
158
159impl Default for FunctionBody {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct LocalVariable {
167 pub id: LocalId,
168 pub name: String,
169 pub var_type: Type,
170 pub location: DataLocation,
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
174pub struct LocalId(pub u32);
175
176pub struct CraneliftFunction {
177 pub func: clif_ir::Function,
178}
179
180impl std::fmt::Debug for CraneliftFunction {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 f.debug_struct("CraneliftFunction")
183 .field("name", &self.func.name)
184 .finish()
185 }
186}
187
188impl Clone for CraneliftFunction {
189 fn clone(&self) -> Self {
190 Self {
191 func: self.func.clone(),
192 }
193 }
194}
195
196#[derive(Debug, Clone, Default, Serialize, Deserialize)]
197pub struct FunctionMetadata {
198 pub is_constructor: bool,
199 pub is_fallback: bool,
200 pub is_receive: bool,
201 pub estimated_gas: Option<u64>,
202 pub can_reenter: bool,
203 pub has_assembly: bool,
204 pub calls_external: bool,
205 pub modifies_state: bool,
206}