1use crate::{
6 prelude::{ChiselDispatcher, ChiselResult, ChiselRunner, SessionSource, SolidityHelper},
7 source::IntermediateOutput,
8};
9use alloy_dyn_abi::{DynSolType, DynSolValue};
10use alloy_json_abi::EventParam;
11use alloy_primitives::{Address, B256, U256, hex};
12use eyre::{Result, WrapErr};
13use foundry_compilers::Artifact;
14use foundry_evm::{
15 backend::Backend, decode::decode_console_logs, executors::ExecutorBuilder,
16 inspectors::CheatsConfig, traces::TraceMode,
17};
18use solang_parser::pt;
19use std::ops::ControlFlow;
20use yansi::Paint;
21
22impl SessionSource {
24 pub async fn execute(&mut self) -> Result<ChiselResult> {
26 let output = self.build()?;
28
29 let (bytecode, final_pc) = output.enter(|output| -> Result<_> {
30 let contract = output
31 .repl_contract()
32 .ok_or_else(|| eyre::eyre!("failed to find REPL contract"))?;
33 trace!(?contract, "REPL contract");
34 let bytecode = contract
35 .get_bytecode_bytes()
36 .ok_or_else(|| eyre::eyre!("No bytecode found for `REPL` contract"))?;
37 Ok((bytecode.into_owned(), output.final_pc(contract)?))
38 })?;
39 let final_pc = final_pc.unwrap_or_default();
40 let mut runner = self.build_runner(final_pc).await?;
41 runner.run(bytecode)
42 }
43
44 pub async fn inspect(&self, input: &str) -> Result<(ControlFlow<()>, Option<String>)> {
56 let line = format!("bytes memory inspectoor = abi.encode({input});");
57 let mut source = match self.clone_with_new_line(line) {
58 Ok((source, _)) => source,
59 Err(err) => {
60 debug!(%err, "failed to build new source for inspection");
61 return Ok((ControlFlow::Continue(()), None));
62 }
63 };
64
65 let mut source_without_inspector = self.clone();
66
67 let (mut res, err) = match source.execute().await {
70 Ok(res) => (res, None),
71 Err(err) => {
72 debug!(?err, %input, "execution failed");
73 match source_without_inspector.execute().await {
74 Ok(res) => (res, Some(err)),
75 Err(_) => {
76 if self.config.foundry_config.verbosity >= 3 {
77 sh_err!("Could not inspect: {err}")?;
78 }
79 return Ok((ControlFlow::Continue(()), None));
80 }
81 }
82 }
83 };
84
85 if let Some(err) = err {
87 let output = source_without_inspector.build()?;
88
89 let formatted_event =
90 output.enter(|output| output.get_event(input).map(format_event_definition));
91 if let Some(formatted_event) = formatted_event {
92 return Ok((ControlFlow::Break(()), Some(formatted_event?)));
93 }
94
95 if self.config.foundry_config.verbosity >= 3 {
97 sh_err!("Failed eval: {err}")?;
98 }
99
100 debug!(%err, %input, "failed abi encode input");
101 return Ok((ControlFlow::Break(()), None));
102 }
103 drop(source_without_inspector);
104
105 let Some((stack, memory)) = &res.state else {
106 if let Ok(decoder) = ChiselDispatcher::decode_traces(&source.config, &mut res).await {
108 ChiselDispatcher::show_traces(&decoder, &mut res).await?;
109 }
110 let decoded_logs = decode_console_logs(&res.logs);
111 if !decoded_logs.is_empty() {
112 sh_println!("{}", "Logs:".green())?;
113 for log in decoded_logs {
114 sh_println!(" {log}")?;
115 }
116 }
117
118 return Err(eyre::eyre!("Failed to inspect expression"));
119 };
120
121 let generated_output = source.build()?;
124
125 let contract_expr = generated_output
128 .intermediate
129 .repl_contract_expressions
130 .get(input)
131 .or_else(|| source.infer_inner_expr_type());
132
133 let function_call_return_type =
136 Type::get_function_return_type(contract_expr, &generated_output.intermediate);
137
138 let (contract_expr, ty) = if let Some(function_call_return_type) = function_call_return_type
139 {
140 (function_call_return_type.0, function_call_return_type.1)
141 } else {
142 match contract_expr.and_then(|e| {
143 Type::ethabi(e, Some(&generated_output.intermediate)).map(|ty| (e, ty))
144 }) {
145 Some(res) => res,
146 None => return Ok((ControlFlow::Continue(()), None)),
148 }
149 };
150
151 let data = (|| -> Option<_> {
154 let mut offset: usize = stack.last()?.try_into().ok()?;
155 debug!("inspect memory @ {offset}: {}", hex::encode(memory));
156 let mem_offset = memory.get(offset..offset + 32)?;
157 let len: usize = U256::try_from_be_slice(mem_offset)?.try_into().ok()?;
158 offset += 32;
159 memory.get(offset..offset + len)
160 })();
161 let Some(data) = data else {
162 eyre::bail!("Failed to inspect last expression: could not retrieve data from memory")
163 };
164 let token = ty.abi_decode(data).wrap_err("Could not decode inspected values")?;
165 let c = if should_continue(contract_expr) {
166 ControlFlow::Continue(())
167 } else {
168 ControlFlow::Break(())
169 };
170 Ok((c, Some(format_token(token))))
171 }
172
173 fn infer_inner_expr_type(&self) -> Option<&pt::Expression> {
184 let out = self.build().ok()?;
185 let run = out.run_func_body().ok()?.last();
186 match run {
187 Some(pt::Statement::VariableDefinition(
188 _,
189 _,
190 Some(pt::Expression::FunctionCall(_, _, args)),
191 )) => {
192 Some(args.first().unwrap())
196 }
197 _ => None,
198 }
199 }
200
201 async fn build_runner(&mut self, final_pc: usize) -> Result<ChiselRunner> {
202 let (evm_env, tx_env, fork_block) = self.config.evm_opts.env().await?;
203
204 let backend = match self.config.backend.clone() {
205 Some(backend) => backend,
206 None => {
207 let fork = self.config.evm_opts.get_fork(
208 &self.config.foundry_config,
209 evm_env.cfg_env.chain_id,
210 fork_block,
211 );
212 let backend = Backend::spawn(fork)?;
213 self.config.backend = Some(backend.clone());
214 backend
215 }
216 };
217
218 let executor = ExecutorBuilder::default()
219 .inspectors(|stack| {
220 stack
221 .logs(self.config.foundry_config.live_logs)
222 .chisel_state(final_pc)
223 .trace_mode(TraceMode::Call)
224 .cheatcodes(
225 CheatsConfig::new(
226 &self.config.foundry_config,
227 self.config.evm_opts.clone(),
228 None,
229 None,
230 None,
231 )
232 .into(),
233 )
234 })
235 .gas_limit(self.config.evm_opts.gas_limit())
236 .spec_id(self.config.foundry_config.evm_spec_id())
237 .legacy_assertions(self.config.foundry_config.legacy_assertions)
238 .build(evm_env, tx_env, backend);
239
240 Ok(ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone()))
241 }
242}
243
244fn format_token(token: DynSolValue) -> String {
247 match token {
248 DynSolValue::Address(a) => {
249 format!("Type: {}\n└ Data: {}", "address".red(), a.cyan())
250 }
251 DynSolValue::FixedBytes(b, byte_len) => {
252 format!(
253 "Type: {}\n└ Data: {}",
254 format!("bytes{byte_len}").red(),
255 hex::encode_prefixed(b).cyan()
256 )
257 }
258 DynSolValue::Int(i, bit_len) => {
259 format!(
260 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
261 format!("int{bit_len}").red(),
262 format!(
263 "0x{}",
264 format!("{i:x}")
265 .chars()
266 .skip(if i.is_negative() { 64 - bit_len / 4 } else { 0 })
267 .collect::<String>()
268 )
269 .cyan(),
270 hex::encode_prefixed(B256::from(i)).cyan(),
271 i.cyan()
272 )
273 }
274 DynSolValue::Uint(i, bit_len) => {
275 format!(
276 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
277 format!("uint{bit_len}").red(),
278 format!("0x{i:x}").cyan(),
279 hex::encode_prefixed(B256::from(i)).cyan(),
280 i.cyan()
281 )
282 }
283 DynSolValue::Bool(b) => {
284 format!("Type: {}\n└ Value: {}", "bool".red(), b.cyan())
285 }
286 DynSolValue::String(_) | DynSolValue::Bytes(_) => {
287 let hex = hex::encode(token.abi_encode());
288 let s = token.as_str();
289 format!(
290 "Type: {}\n{}├ Hex (Memory):\n├─ Length ({}): {}\n├─ Contents ({}): {}\n├ Hex (Tuple Encoded):\n├─ Pointer ({}): {}\n├─ Length ({}): {}\n└─ Contents ({}): {}",
291 if s.is_some() { "string" } else { "dynamic bytes" }.red(),
292 if let Some(s) = s {
293 format!("├ UTF-8: {}\n", s.cyan())
294 } else {
295 String::default()
296 },
297 "[0x00:0x20]".yellow(),
298 format!("0x{}", &hex[64..128]).cyan(),
299 "[0x20:..]".yellow(),
300 format!("0x{}", &hex[128..]).cyan(),
301 "[0x00:0x20]".yellow(),
302 format!("0x{}", &hex[..64]).cyan(),
303 "[0x20:0x40]".yellow(),
304 format!("0x{}", &hex[64..128]).cyan(),
305 "[0x40:..]".yellow(),
306 format!("0x{}", &hex[128..]).cyan(),
307 )
308 }
309 DynSolValue::FixedArray(tokens) | DynSolValue::Array(tokens) => {
310 let mut out = format!(
311 "{}({}) = {}",
312 "array".red(),
313 format!("{}", tokens.len()).yellow(),
314 '['.red()
315 );
316 for token in tokens {
317 out.push_str("\n ├ ");
318 out.push_str(&format_token(token).replace('\n', "\n "));
319 out.push('\n');
320 }
321 out.push_str(&']'.red().to_string());
322 out
323 }
324 DynSolValue::Tuple(tokens) => {
325 let displayed_types = tokens
326 .iter()
327 .map(|t| t.sol_type_name().unwrap_or_default())
328 .collect::<Vec<_>>()
329 .join(", ");
330 let mut out =
331 format!("{}({}) = {}", "tuple".red(), displayed_types.yellow(), '('.red());
332 for token in tokens {
333 out.push_str("\n ├ ");
334 out.push_str(&format_token(token).replace('\n', "\n "));
335 out.push('\n');
336 }
337 out.push_str(&')'.red().to_string());
338 out
339 }
340 _ => {
341 unimplemented!()
342 }
343 }
344}
345
346fn format_event_definition(event_definition: &pt::EventDefinition) -> Result<String> {
357 let event_name = event_definition.name.as_ref().expect("Event has a name").to_string();
358 let inputs = event_definition
359 .fields
360 .iter()
361 .map(|param| {
362 let name = param
363 .name
364 .as_ref()
365 .map(ToString::to_string)
366 .unwrap_or_else(|| "<anonymous>".to_string());
367 let kind = Type::from_expression(¶m.ty)
368 .and_then(Type::into_builtin)
369 .ok_or_else(|| eyre::eyre!("Invalid type in event {event_name}"))?;
370 Ok(EventParam {
371 name,
372 ty: kind.to_string(),
373 components: vec![],
374 indexed: param.indexed,
375 internal_type: None,
376 })
377 })
378 .collect::<Result<Vec<_>>>()?;
379 let event =
380 alloy_json_abi::Event { name: event_name, inputs, anonymous: event_definition.anonymous };
381
382 Ok(format!(
383 "Type: {}\n├ Name: {}\n├ Signature: {:?}\n└ Selector: {:?}",
384 "event".red(),
385 SolidityHelper::new().highlight(&format!(
386 "{}({})",
387 &event.name,
388 &event
389 .inputs
390 .iter()
391 .map(|param| format!(
392 "{}{}{}",
393 param.ty,
394 if param.indexed { " indexed" } else { "" },
395 if param.name.is_empty() {
396 String::default()
397 } else {
398 format!(" {}", ¶m.name)
399 },
400 ))
401 .collect::<Vec<_>>()
402 .join(", ")
403 )),
404 event.signature().cyan(),
405 event.selector().cyan(),
406 ))
407}
408
409#[derive(Clone, Debug, PartialEq)]
415enum Type {
416 Builtin(DynSolType),
418
419 Array(Box<Self>),
421
422 FixedArray(Box<Self>, usize),
424
425 ArrayIndex(Box<Self>, Option<usize>),
427
428 Tuple(Vec<Option<Self>>),
430
431 Function(Box<Self>, Vec<Option<Self>>, Vec<Option<Self>>),
433
434 Access(Box<Self>, String),
436
437 Custom(Vec<String>),
439}
440
441impl Type {
442 fn from_expression(expr: &pt::Expression) -> Option<Self> {
452 match expr {
453 pt::Expression::Type(_, ty) => Self::from_type(ty),
454
455 pt::Expression::Variable(ident) => Some(Self::Custom(vec![ident.name.clone()])),
456
457 pt::Expression::ArraySubscript(_, expr, num) => {
459 Self::from_expression(expr).and_then(|ty| {
462 let boxed = Box::new(ty);
463 let num = num.as_deref().and_then(parse_number_literal).and_then(|n| {
464 usize::try_from(n).ok()
465 });
466 match expr.as_ref() {
467 pt::Expression::Type(_, _) => {
469 if let Some(num) = num {
470 Some(Self::FixedArray(boxed, num))
471 } else {
472 Some(Self::Array(boxed))
473 }
474 }
475 pt::Expression::Variable(_) => {
477 Some(Self::ArrayIndex(boxed, num))
478 }
479 _ => None
480 }
481 })
482 }
483 pt::Expression::ArrayLiteral(_, values) => {
484 values.first().and_then(Self::from_expression).map(|ty| {
485 Self::FixedArray(Box::new(ty), values.len())
486 })
487 }
488
489 pt::Expression::List(_, params) => Some(Self::Tuple(map_parameters(params))),
491
492 pt::Expression::MemberAccess(_, lhs, rhs) => {
494 Self::from_expression(lhs).map(|lhs| {
495 Self::Access(Box::new(lhs), rhs.name.clone())
496 })
497 }
498
499 pt::Expression::Parenthesis(_, inner) | pt::Expression::New(_, inner) | pt::Expression::UnaryPlus(_, inner) | pt::Expression::BitwiseNot(_, inner) | pt::Expression::ArraySlice(_, inner, _, _) | pt::Expression::PreDecrement(_, inner) | pt::Expression::PostDecrement(_, inner) | pt::Expression::PreIncrement(_, inner) | pt::Expression::PostIncrement(_, inner) | pt::Expression::Assign(_, inner, _) | pt::Expression::AssignAdd(_, inner, _) | pt::Expression::AssignSubtract(_, inner, _) | pt::Expression::AssignMultiply(_, inner, _) | pt::Expression::AssignDivide(_, inner, _) | pt::Expression::AssignModulo(_, inner, _) | pt::Expression::AssignAnd(_, inner, _) | pt::Expression::AssignOr(_, inner, _) | pt::Expression::AssignXor(_, inner, _) | pt::Expression::AssignShiftLeft(_, inner, _) | pt::Expression::AssignShiftRight(_, inner, _) => Self::from_expression(inner),
523
524 pt::Expression::ConditionalOperator(_, _, if_true, if_false) => {
526 Self::from_expression(if_true).or_else(|| Self::from_expression(if_false))
527 }
528
529 pt::Expression::AddressLiteral(_, _) => Some(Self::Builtin(DynSolType::Address)),
531 pt::Expression::HexNumberLiteral(_, s, _) => {
532 match s.parse::<Address>() {
533 Ok(addr) if *s == addr.to_checksum(None) => {
534 Some(Self::Builtin(DynSolType::Address))
535 }
536 _ => Some(Self::Builtin(DynSolType::Uint(256))),
537 }
538 }
539
540 pt::Expression::Negate(_, inner) => Self::from_expression(inner).map(Self::invert_int),
543
544 pt::Expression::Add(_, lhs, rhs) |
548 pt::Expression::Subtract(_, lhs, rhs) |
549 pt::Expression::Multiply(_, lhs, rhs) |
550 pt::Expression::Divide(_, lhs, rhs) => {
551 match (Self::ethabi(lhs, None), Self::ethabi(rhs, None)) {
552 (Some(DynSolType::Int(_) | DynSolType::Uint(_)), Some(DynSolType::Int(_))) |
553(Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) => {
554 Some(Self::Builtin(DynSolType::Int(256)))
555 }
556 _ => {
557 Some(Self::Builtin(DynSolType::Uint(256)))
558 }
559 }
560 }
561
562 pt::Expression::Modulo(_, _, _) |
564 pt::Expression::Power(_, _, _) |
565 pt::Expression::BitwiseOr(_, _, _) |
566 pt::Expression::BitwiseAnd(_, _, _) |
567 pt::Expression::BitwiseXor(_, _, _) |
568 pt::Expression::ShiftRight(_, _, _) |
569 pt::Expression::ShiftLeft(_, _, _) |
570 pt::Expression::NumberLiteral(_, _, _, _) => Some(Self::Builtin(DynSolType::Uint(256))),
571
572 pt::Expression::RationalNumberLiteral(_, _, _, _, _) => {
574 Some(Self::Builtin(DynSolType::Uint(256)))
575 }
576
577 pt::Expression::BoolLiteral(_, _) |
579 pt::Expression::And(_, _, _) |
580 pt::Expression::Or(_, _, _) |
581 pt::Expression::Equal(_, _, _) |
582 pt::Expression::NotEqual(_, _, _) |
583 pt::Expression::Less(_, _, _) |
584 pt::Expression::LessEqual(_, _, _) |
585 pt::Expression::More(_, _, _) |
586 pt::Expression::MoreEqual(_, _, _) |
587 pt::Expression::Not(_, _) => Some(Self::Builtin(DynSolType::Bool)),
588
589 pt::Expression::StringLiteral(_) => Some(Self::Builtin(DynSolType::String)),
591
592 pt::Expression::HexLiteral(_) => Some(Self::Builtin(DynSolType::Bytes)),
594
595 pt::Expression::FunctionCall(_, name, args) => {
597 Self::from_expression(name).map(|name| {
598 let args = args.iter().map(Self::from_expression).collect();
599 Self::Function(Box::new(name), args, vec![])
600 })
601 }
602 pt::Expression::NamedFunctionCall(_, name, args) => {
603 Self::from_expression(name).map(|name| {
604 let args = args.iter().map(|arg| Self::from_expression(&arg.expr)).collect();
605 Self::Function(Box::new(name), args, vec![])
606 })
607 }
608
609 pt::Expression::Delete(_, _) | pt::Expression::FunctionCallBlock(_, _, _) => None,
611 }
612 }
613
614 fn from_type(ty: &pt::Type) -> Option<Self> {
624 let ty = match ty {
625 pt::Type::Address | pt::Type::AddressPayable | pt::Type::Payable => {
626 Self::Builtin(DynSolType::Address)
627 }
628 pt::Type::Bool => Self::Builtin(DynSolType::Bool),
629 pt::Type::String => Self::Builtin(DynSolType::String),
630 pt::Type::Int(size) => Self::Builtin(DynSolType::Int(*size as usize)),
631 pt::Type::Uint(size) => Self::Builtin(DynSolType::Uint(*size as usize)),
632 pt::Type::Bytes(size) => Self::Builtin(DynSolType::FixedBytes(*size as usize)),
633 pt::Type::DynamicBytes => Self::Builtin(DynSolType::Bytes),
634 pt::Type::Mapping { value, .. } => Self::from_expression(value)?,
635 pt::Type::Function { params, returns, .. } => {
636 let params = map_parameters(params);
637 let returns = returns
638 .as_ref()
639 .map(|(returns, _)| map_parameters(returns))
640 .unwrap_or_default();
641 Self::Function(
642 Box::new(Self::Custom(vec!["__fn_type__".to_string()])),
643 params,
644 returns,
645 )
646 }
647 pt::Type::Rational => return None,
649 };
650 Some(ty)
651 }
652
653 fn map_special(self) -> Self {
657 if !matches!(self, Self::Function(_, _, _) | Self::Access(_, _) | Self::Custom(_)) {
658 return self;
659 }
660
661 let mut types = Vec::with_capacity(5);
662 let mut args = None;
663 self.recurse(&mut types, &mut args);
664
665 let len = types.len();
666 if len == 0 {
667 return self;
668 }
669
670 #[expect(clippy::single_match)]
672 #[allow(clippy::collapsible_match)]
673 match &self {
674 Self::Access(inner, access) => {
675 if let Some(ty) = inner.as_ref().clone().try_as_ethabi(None) {
676 let ty = Self::Builtin(ty);
678 match access.as_str() {
679 "length" if ty.is_dynamic() || ty.is_array() || ty.is_fixed_bytes() => {
680 return Self::Builtin(DynSolType::Uint(256));
681 }
682 "pop" if ty.is_dynamic_array() => return ty,
683 _ => {}
684 }
685 }
686 }
687 _ => {}
688 }
689
690 let this = {
691 let name = types.last().unwrap().as_str();
692 match len {
693 0 => unreachable!(),
694 1 => match name {
695 "gasleft" | "addmod" | "mulmod" => Some(DynSolType::Uint(256)),
696 "keccak256" | "sha256" | "blockhash" => Some(DynSolType::FixedBytes(32)),
697 "ripemd160" => Some(DynSolType::FixedBytes(20)),
698 "ecrecover" => Some(DynSolType::Address),
699 _ => None,
700 },
701 2 => {
702 let access = types.first().unwrap().as_str();
703 match name {
704 "block" => match access {
705 "coinbase" => Some(DynSolType::Address),
706 "timestamp" | "difficulty" | "prevrandao" | "number" | "gaslimit"
707 | "chainid" | "basefee" | "blobbasefee" => Some(DynSolType::Uint(256)),
708 _ => None,
709 },
710 "msg" => match access {
711 "sender" => Some(DynSolType::Address),
712 "gas" => Some(DynSolType::Uint(256)),
713 "value" => Some(DynSolType::Uint(256)),
714 "data" => Some(DynSolType::Bytes),
715 "sig" => Some(DynSolType::FixedBytes(4)),
716 _ => None,
717 },
718 "tx" => match access {
719 "origin" => Some(DynSolType::Address),
720 "gasprice" => Some(DynSolType::Uint(256)),
721 _ => None,
722 },
723 "abi" => match access {
724 "decode" => {
725 let mut args = args.unwrap();
729 let last = args.pop().unwrap();
730 match last {
731 Some(ty) => {
732 return match ty {
733 Self::Tuple(_) => ty,
734 ty => Self::Tuple(vec![Some(ty)]),
735 };
736 }
737 None => None,
738 }
739 }
740 s if s.starts_with("encode") => Some(DynSolType::Bytes),
741 _ => None,
742 },
743 "address" => match access {
744 "balance" => Some(DynSolType::Uint(256)),
745 "code" => Some(DynSolType::Bytes),
746 "codehash" => Some(DynSolType::FixedBytes(32)),
747 "send" => Some(DynSolType::Bool),
748 _ => None,
749 },
750 "type" => match access {
751 "name" => Some(DynSolType::String),
752 "creationCode" | "runtimeCode" => Some(DynSolType::Bytes),
753 "interfaceId" => Some(DynSolType::FixedBytes(4)),
754 "min" | "max" => Some(
755 (|| args?.pop()??.into_builtin())()
757 .unwrap_or(DynSolType::Uint(256)),
758 ),
759 _ => None,
760 },
761 "string" => match access {
762 "concat" => Some(DynSolType::String),
763 _ => None,
764 },
765 "bytes" => match access {
766 "concat" => Some(DynSolType::Bytes),
767 _ => None,
768 },
769 _ => None,
770 }
771 }
772 _ => None,
773 }
774 };
775
776 this.map(Self::Builtin).unwrap_or_else(|| match types.last().unwrap().as_str() {
777 "this" | "super" => Self::Custom(types),
778 _ => match self {
779 Self::Custom(_) | Self::Access(_, _) => Self::Custom(types),
780 Self::Function(_, _, _) => self,
781 _ => unreachable!(),
782 },
783 })
784 }
785
786 fn recurse(&self, types: &mut Vec<String>, args: &mut Option<Vec<Option<Self>>>) {
789 match self {
790 Self::Builtin(ty) => types.push(ty.to_string()),
791 Self::Custom(tys) => types.extend(tys.clone()),
792 Self::Access(expr, name) => {
793 types.push(name.clone());
794 expr.recurse(types, args);
795 }
796 Self::Function(fn_name, fn_args, _fn_ret) => {
797 if args.is_none() && !fn_args.is_empty() {
798 *args = Some(fn_args.clone());
799 }
800 fn_name.recurse(types, args);
801 }
802 _ => {}
803 }
804 }
805
806 fn infer_custom_type(
820 intermediate: &IntermediateOutput,
821 custom_type: &mut Vec<String>,
822 contract_name: Option<String>,
823 ) -> Result<Option<DynSolType>> {
824 if let Some("this" | "super") = custom_type.last().map(String::as_str) {
825 custom_type.pop();
826 }
827 if custom_type.is_empty() {
828 return Ok(None);
829 }
830
831 if let Some(contract_name) = contract_name {
834 let intermediate_contract = intermediate
835 .intermediate_contracts
836 .get(&contract_name)
837 .ok_or_else(|| eyre::eyre!("Could not find intermediate contract!"))?;
838
839 let cur_type = custom_type.last().unwrap();
840 if let Some(func) = intermediate_contract.function_definitions.get(cur_type) {
841 if let res @ Some(_) = func_members(func, custom_type) {
843 return Ok(res);
844 }
845
846 if func.returns.is_empty() {
849 eyre::bail!(
850 "This call expression does not return any values to inspect. Insert as statement."
851 )
852 }
853
854 let (_, param) = func.returns.first().unwrap();
856 let return_ty = ¶m.as_ref().unwrap().ty;
858
859 if let pt::Expression::Variable(ident) = return_ty {
863 custom_type.push(ident.name.clone());
864 return Self::infer_custom_type(intermediate, custom_type, Some(contract_name));
865 }
866
867 if let Some(pt::FunctionAttribute::Mutability(_mut)) = func
871 .attributes
872 .iter()
873 .find(|attr| matches!(attr, pt::FunctionAttribute::Mutability(_)))
874 {
875 if let pt::Mutability::Payable(_) = _mut {
876 eyre::bail!("This function mutates state. Insert as a statement.")
877 }
878 } else {
879 eyre::bail!("This function mutates state. Insert as a statement.")
880 }
881
882 Ok(Self::ethabi(return_ty, Some(intermediate)))
883 } else if let Some(var) = intermediate_contract.variable_definitions.get(cur_type) {
884 Self::infer_var_expr(&var.ty, Some(intermediate), custom_type)
885 } else if let Some(strukt) = intermediate_contract.struct_definitions.get(cur_type) {
886 let inner_types = strukt
887 .fields
888 .iter()
889 .map(|var| {
890 Self::ethabi(&var.ty, Some(intermediate))
891 .ok_or_else(|| eyre::eyre!("Struct `{cur_type}` has invalid fields"))
892 })
893 .collect::<Result<Vec<_>>>()?;
894 Ok(Some(DynSolType::Tuple(inner_types)))
895 } else {
896 eyre::bail!(
897 "Could not find any definition in contract \"{contract_name}\" for type: {custom_type:?}"
898 )
899 }
900 } else {
901 if let Ok(res) = Self::infer_custom_type(intermediate, custom_type, Some("REPL".into()))
904 {
905 return Ok(res);
906 }
907
908 let name = custom_type.last().unwrap();
911 let contract = intermediate.intermediate_contracts.get(name);
912 if contract.is_some() {
913 let contract_name = custom_type.pop();
914 return Self::infer_custom_type(intermediate, custom_type, contract_name);
915 }
916
917 let name = custom_type.last().unwrap();
919 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
920 return Self::infer_var_expr(expr, Some(intermediate), custom_type);
921 }
922
923 Ok(None)
926 }
927 }
928
929 fn infer_var_expr(
931 expr: &pt::Expression,
932 intermediate: Option<&IntermediateOutput>,
933 custom_type: &mut Vec<String>,
934 ) -> Result<Option<DynSolType>> {
935 let res = match &expr {
937 pt::Expression::Variable(ident) => {
939 let name = &ident.name;
940
941 if let Some(intermediate) = intermediate {
942 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
944 Self::infer_var_expr(expr, Some(intermediate), custom_type)
945 } else if intermediate.intermediate_contracts.contains_key(name) {
946 if custom_type.len() > 1 {
947 custom_type.pop();
949 Self::infer_custom_type(intermediate, custom_type, Some(name.clone()))
950 } else {
951 Ok(Some(DynSolType::Address))
953 }
954 } else {
955 Err(eyre::eyre!("Could not infer variable type"))
956 }
957 } else {
958 Ok(None)
959 }
960 }
961 other_expr => Ok(Self::ethabi(other_expr, intermediate)),
962 };
963 match res {
966 Ok(Some(ty)) => {
967 let box_ty = Box::new(Self::Builtin(ty.clone()));
968 let access = Self::Access(box_ty, custom_type.drain(..).next().unwrap_or_default());
969 if let Some(mapped) = access.map_special().try_as_ethabi(intermediate) {
970 Ok(Some(mapped))
971 } else {
972 Ok(Some(ty))
973 }
974 }
975 res => res,
976 }
977 }
978
979 fn try_as_ethabi(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
987 match self {
988 Self::Builtin(ty) => Some(ty),
989 Self::Tuple(types) => Some(DynSolType::Tuple(types_to_parameters(types, intermediate))),
990 Self::Array(inner) => match *inner {
991 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
992 _ => inner
993 .try_as_ethabi(intermediate)
994 .map(|inner| DynSolType::Array(Box::new(inner))),
995 },
996 Self::FixedArray(inner, size) => match *inner {
997 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
998 _ => inner
999 .try_as_ethabi(intermediate)
1000 .map(|inner| DynSolType::FixedArray(Box::new(inner), size)),
1001 },
1002 ty @ Self::ArrayIndex(_, _) => ty.into_array_index(intermediate),
1003 Self::Function(ty, _, _) => ty.try_as_ethabi(intermediate),
1004 Self::Access(_, _) => None,
1006 Self::Custom(mut types) => {
1007 intermediate.and_then(|intermediate| {
1009 Self::infer_custom_type(intermediate, &mut types, None).ok().flatten()
1010 })
1011 }
1012 }
1013 }
1014
1015 fn ethabi(
1017 expr: &pt::Expression,
1018 intermediate: Option<&IntermediateOutput>,
1019 ) -> Option<DynSolType> {
1020 Self::from_expression(expr)
1021 .map(Self::map_special)
1022 .and_then(|ty| ty.try_as_ethabi(intermediate))
1023 }
1024
1025 fn get_function_return_type<'a>(
1027 contract_expr: Option<&'a pt::Expression>,
1028 intermediate: &IntermediateOutput,
1029 ) -> Option<(&'a pt::Expression, DynSolType)> {
1030 let function_call = match contract_expr? {
1031 pt::Expression::FunctionCall(_, function_call, _) => function_call,
1032 _ => return None,
1033 };
1034 let (contract_name, function_name) = match function_call.as_ref() {
1035 pt::Expression::MemberAccess(_, contract_name, function_name) => {
1036 (contract_name, function_name)
1037 }
1038 _ => return None,
1039 };
1040 let contract_name = match contract_name.as_ref() {
1041 pt::Expression::Variable(contract_name) => contract_name.to_owned(),
1042 _ => return None,
1043 };
1044
1045 let pt::Expression::Variable(contract_name) =
1046 intermediate.repl_contract_expressions.get(&contract_name.name)?
1047 else {
1048 return None;
1049 };
1050
1051 let contract = intermediate
1052 .intermediate_contracts
1053 .get(&contract_name.name)?
1054 .function_definitions
1055 .get(&function_name.name)?;
1056 let return_parameter = contract.as_ref().returns.first()?.to_owned().1?;
1057 Self::ethabi(&return_parameter.ty, Some(intermediate)).map(|p| (contract_expr.unwrap(), p))
1058 }
1059
1060 fn invert_int(self) -> Self {
1062 match self {
1063 Self::Builtin(DynSolType::Uint(n)) => Self::Builtin(DynSolType::Int(n)),
1064 Self::Builtin(DynSolType::Int(n)) => Self::Builtin(DynSolType::Uint(n)),
1065 x => x,
1066 }
1067 }
1068
1069 #[inline]
1071 fn into_builtin(self) -> Option<DynSolType> {
1072 match self {
1073 Self::Builtin(ty) => Some(ty),
1074 _ => None,
1075 }
1076 }
1077
1078 fn into_array_index(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
1080 match self {
1081 Self::Array(inner) | Self::FixedArray(inner, _) | Self::ArrayIndex(inner, _) => {
1082 match inner.try_as_ethabi(intermediate) {
1083 Some(DynSolType::Array(inner) | DynSolType::FixedArray(inner, _)) => {
1084 Some(*inner)
1085 }
1086 Some(DynSolType::Bytes | DynSolType::String | DynSolType::FixedBytes(_)) => {
1087 Some(DynSolType::FixedBytes(1))
1088 }
1089 ty => ty,
1090 }
1091 }
1092 _ => None,
1093 }
1094 }
1095
1096 #[inline]
1098 fn is_dynamic(&self) -> bool {
1099 match self {
1100 Self::Builtin(DynSolType::Bytes | DynSolType::String | DynSolType::Array(_)) => true,
1103 Self::Array(_) => true,
1104 _ => false,
1105 }
1106 }
1107
1108 #[inline]
1110 fn is_array(&self) -> bool {
1111 matches!(
1112 self,
1113 Self::Array(_)
1114 | Self::FixedArray(_, _)
1115 | Self::Builtin(DynSolType::Array(_) | DynSolType::FixedArray(_, _))
1116 )
1117 }
1118
1119 #[inline]
1121 fn is_dynamic_array(&self) -> bool {
1122 matches!(self, Self::Array(_) | Self::Builtin(DynSolType::Array(_)))
1123 }
1124
1125 fn is_fixed_bytes(&self) -> bool {
1126 matches!(self, Self::Builtin(DynSolType::FixedBytes(_)))
1127 }
1128}
1129
1130#[inline]
1134fn func_members(func: &pt::FunctionDefinition, custom_type: &[String]) -> Option<DynSolType> {
1135 if !matches!(func.ty, pt::FunctionTy::Function) {
1136 return None;
1137 }
1138
1139 let vis = func.attributes.iter().find_map(|attr| match attr {
1140 pt::FunctionAttribute::Visibility(vis) => Some(vis),
1141 _ => None,
1142 });
1143 match vis {
1144 Some(pt::Visibility::External(_) | pt::Visibility::Public(_)) => {
1145 match custom_type.first().unwrap().as_str() {
1146 "address" => Some(DynSolType::Address),
1147 "selector" => Some(DynSolType::FixedBytes(4)),
1148 _ => None,
1149 }
1150 }
1151 _ => None,
1152 }
1153}
1154
1155#[inline]
1157fn should_continue(expr: &pt::Expression) -> bool {
1158 match expr {
1159 pt::Expression::PreDecrement(_, _) | pt::Expression::PostDecrement(_, _) | pt::Expression::PreIncrement(_, _) | pt::Expression::PostIncrement(_, _) | pt::Expression::Assign(_, _, _) | pt::Expression::AssignAdd(_, _, _) | pt::Expression::AssignSubtract(_, _, _) | pt::Expression::AssignMultiply(_, _, _) | pt::Expression::AssignDivide(_, _, _) | pt::Expression::AssignModulo(_, _, _) | pt::Expression::AssignAnd(_, _, _) | pt::Expression::AssignOr(_, _, _) | pt::Expression::AssignXor(_, _, _) | pt::Expression::AssignShiftLeft(_, _, _) | pt::Expression::AssignShiftRight(_, _, _) => {
1176 true
1177 }
1178
1179 pt::Expression::FunctionCall(_, lhs, _) => {
1181 match lhs.as_ref() {
1182 pt::Expression::MemberAccess(_, _inner, access) => access.name == "pop",
1183 _ => false
1184 }
1185 }
1186
1187 _ => false
1188 }
1189}
1190
1191fn map_parameters(params: &[(pt::Loc, Option<pt::Parameter>)]) -> Vec<Option<Type>> {
1192 params
1193 .iter()
1194 .map(|(_, param)| param.as_ref().and_then(|param| Type::from_expression(¶m.ty)))
1195 .collect()
1196}
1197
1198fn types_to_parameters(
1199 types: Vec<Option<Type>>,
1200 intermediate: Option<&IntermediateOutput>,
1201) -> Vec<DynSolType> {
1202 types.into_iter().filter_map(|ty| ty.and_then(|ty| ty.try_as_ethabi(intermediate))).collect()
1203}
1204
1205fn parse_number_literal(expr: &pt::Expression) -> Option<U256> {
1206 match expr {
1207 pt::Expression::NumberLiteral(_, num, exp, unit) => {
1208 let num = num.parse::<U256>().unwrap_or(U256::ZERO);
1209 let exp = exp.parse().unwrap_or(0u32);
1210 if exp > 77 {
1211 None
1212 } else {
1213 let exp = U256::from(10usize.pow(exp));
1214 let unit_mul = unit_multiplier(unit).ok()?;
1215 Some(num * exp * unit_mul)
1216 }
1217 }
1218 pt::Expression::HexNumberLiteral(_, num, unit) => {
1219 let unit_mul = unit_multiplier(unit).ok()?;
1220 num.parse::<U256>().map(|num| num * unit_mul).ok()
1221 }
1222 pt::Expression::RationalNumberLiteral(..) => None,
1224 _ => None,
1225 }
1226}
1227
1228#[inline]
1229fn unit_multiplier(unit: &Option<pt::Identifier>) -> Result<U256> {
1230 if let Some(unit) = unit {
1231 let mul = match unit.name.as_str() {
1232 "seconds" => 1,
1233 "minutes" => 60,
1234 "hours" => 60 * 60,
1235 "days" => 60 * 60 * 24,
1236 "weeks" => 60 * 60 * 24 * 7,
1237 "wei" => 1,
1238 "gwei" => 10_usize.pow(9),
1239 "ether" => 10_usize.pow(18),
1240 other => eyre::bail!("unknown unit: {other}"),
1241 };
1242 Ok(U256::from(mul))
1243 } else {
1244 Ok(U256::from(1))
1245 }
1246}
1247
1248#[cfg(test)]
1249mod tests {
1250 use super::*;
1251 use foundry_compilers::{error::SolcError, solc::Solc};
1252 use std::sync::Mutex;
1253
1254 #[test]
1255 fn test_expressions() {
1256 static EXPRESSIONS: &[(&str, DynSolType)] = {
1257 use DynSolType::*;
1258 &[
1259 ("1 seconds", Uint(256)),
1262 ("1 minutes", Uint(256)),
1263 ("1 hours", Uint(256)),
1264 ("1 days", Uint(256)),
1265 ("1 weeks", Uint(256)),
1266 ("1 wei", Uint(256)),
1267 ("1 gwei", Uint(256)),
1268 ("1 ether", Uint(256)),
1269 ("-1 seconds", Int(256)),
1271 ("-1 minutes", Int(256)),
1272 ("-1 hours", Int(256)),
1273 ("-1 days", Int(256)),
1274 ("-1 weeks", Int(256)),
1275 ("-1 wei", Int(256)),
1276 ("-1 gwei", Int(256)),
1277 ("-1 ether", Int(256)),
1278 ("true ? 1 : 0", Uint(256)),
1280 ("true ? -1 : 0", Int(256)),
1281 ("1 + 1", Uint(256)),
1287 ("1 - 1", Uint(256)),
1288 ("1 * 1", Uint(256)),
1289 ("1 / 1", Uint(256)),
1290 ("1 % 1", Uint(256)),
1291 ("1 ** 1", Uint(256)),
1292 ("1 | 1", Uint(256)),
1293 ("1 & 1", Uint(256)),
1294 ("1 ^ 1", Uint(256)),
1295 ("1 >> 1", Uint(256)),
1296 ("1 << 1", Uint(256)),
1297 ("int(1) + 1", Int(256)),
1299 ("int(1) - 1", Int(256)),
1300 ("int(1) * 1", Int(256)),
1301 ("int(1) / 1", Int(256)),
1302 ("1 + int(1)", Int(256)),
1303 ("1 - int(1)", Int(256)),
1304 ("1 * int(1)", Int(256)),
1305 ("1 / int(1)", Int(256)),
1306 ("uint256 a; a--", Uint(256)),
1310 ("uint256 a; --a", Uint(256)),
1311 ("uint256 a; a++", Uint(256)),
1312 ("uint256 a; ++a", Uint(256)),
1313 ("uint256 a; a = 1", Uint(256)),
1314 ("uint256 a; a += 1", Uint(256)),
1315 ("uint256 a; a -= 1", Uint(256)),
1316 ("uint256 a; a *= 1", Uint(256)),
1317 ("uint256 a; a /= 1", Uint(256)),
1318 ("uint256 a; a %= 1", Uint(256)),
1319 ("uint256 a; a &= 1", Uint(256)),
1320 ("uint256 a; a |= 1", Uint(256)),
1321 ("uint256 a; a ^= 1", Uint(256)),
1322 ("uint256 a; a <<= 1", Uint(256)),
1323 ("uint256 a; a >>= 1", Uint(256)),
1324 ("true && true", Bool),
1328 ("true || true", Bool),
1329 ("true == true", Bool),
1330 ("true != true", Bool),
1331 ("true < true", Bool),
1332 ("true <= true", Bool),
1333 ("true > true", Bool),
1334 ("true >= true", Bool),
1335 ("!true", Bool),
1336 ]
1338 };
1339
1340 let source = &mut source();
1341
1342 let array_expressions: &[(&str, DynSolType)] = &[
1343 ("[1, 2, 3]", fixed_array(DynSolType::Uint(256), 3)),
1344 ("[uint8(1), 2, 3]", fixed_array(DynSolType::Uint(8), 3)),
1345 ("[int8(1), 2, 3]", fixed_array(DynSolType::Int(8), 3)),
1346 ("new uint256[](3)", array(DynSolType::Uint(256))),
1347 ("uint256[] memory a = new uint256[](3);\na[0]", DynSolType::Uint(256)),
1348 ("uint256[] memory a = new uint256[](3);\na[0:3]", array(DynSolType::Uint(256))),
1349 ];
1350 generic_type_test(source, array_expressions);
1351 generic_type_test(source, EXPRESSIONS);
1352 }
1353
1354 #[test]
1355 fn test_types() {
1356 static TYPES: &[(&str, DynSolType)] = {
1357 use DynSolType::*;
1358 &[
1359 ("bool", Bool),
1361 ("true", Bool),
1362 ("false", Bool),
1363 ("uint", Uint(256)),
1367 ("uint(1)", Uint(256)),
1368 ("1", Uint(256)),
1369 ("0x01", Uint(256)),
1370 ("int", Int(256)),
1371 ("int(1)", Int(256)),
1372 ("int(-1)", Int(256)),
1373 ("-1", Int(256)),
1374 ("-0x01", Int(256)),
1375 ("address", Address),
1379 ("address(0)", Address),
1380 ("0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990", Address),
1381 ("payable(0)", Address),
1382 ("payable(address(0))", Address),
1383 ("string", String),
1387 ("string(\"hello world\")", String),
1388 ("\"hello world\"", String),
1389 ("unicode\"hello world 😀\"", String),
1390 ("bytes", Bytes),
1394 ("bytes(\"hello world\")", Bytes),
1395 ("bytes(unicode\"hello world 😀\")", Bytes),
1396 ("hex\"68656c6c6f20776f726c64\"", Bytes),
1397 ]
1399 };
1400
1401 let mut types: Vec<(String, DynSolType)> = Vec::with_capacity(96 + 32 + 100);
1402 for (n, b) in (8..=256).step_by(8).zip(1..=32) {
1403 types.push((format!("uint{n}(0)"), DynSolType::Uint(n)));
1404 types.push((format!("int{n}(0)"), DynSolType::Int(n)));
1405 types.push((format!("bytes{b}(0x00)"), DynSolType::FixedBytes(b)));
1406 }
1407
1408 for n in 0..=32 {
1409 types.push((
1410 format!("uint256[{n}]"),
1411 DynSolType::FixedArray(Box::new(DynSolType::Uint(256)), n),
1412 ));
1413 }
1414
1415 generic_type_test(&mut source(), TYPES);
1416 generic_type_test(&mut source(), &types);
1417 }
1418
1419 #[test]
1420 fn test_global_vars() {
1421 init_tracing();
1422
1423 let global_variables = {
1425 use DynSolType::*;
1426 &[
1427 ("abi.decode(bytes, (uint8[13]))", Tuple(vec![FixedArray(Box::new(Uint(8)), 13)])),
1429 ("abi.decode(bytes, (address, bytes))", Tuple(vec![Address, Bytes])),
1430 ("abi.decode(bytes, (uint112, uint48))", Tuple(vec![Uint(112), Uint(48)])),
1431 ("abi.encode(_, _)", Bytes),
1432 ("abi.encodePacked(_, _)", Bytes),
1433 ("abi.encodeWithSelector(bytes4, _, _)", Bytes),
1434 ("abi.encodeCall(func(), (_, _))", Bytes),
1435 ("abi.encodeWithSignature(string, _, _)", Bytes),
1436 ("bytes.concat()", Bytes),
1440 ("bytes.concat(_)", Bytes),
1441 ("bytes.concat(_, _)", Bytes),
1442 ("string.concat()", String),
1443 ("string.concat(_)", String),
1444 ("string.concat(_, _)", String),
1445 ("block.basefee", Uint(256)),
1449 ("block.chainid", Uint(256)),
1450 ("block.coinbase", Address),
1451 ("block.difficulty", Uint(256)),
1452 ("block.gaslimit", Uint(256)),
1453 ("block.number", Uint(256)),
1454 ("block.timestamp", Uint(256)),
1455 ("gasleft()", Uint(256)),
1459 ("msg.data", Bytes),
1460 ("msg.sender", Address),
1461 ("msg.sig", FixedBytes(4)),
1462 ("msg.value", Uint(256)),
1463 ("tx.gasprice", Uint(256)),
1464 ("tx.origin", Address),
1465 ("blockhash(uint)", FixedBytes(32)),
1476 ("keccak256(bytes)", FixedBytes(32)),
1477 ("sha256(bytes)", FixedBytes(32)),
1478 ("ripemd160(bytes)", FixedBytes(20)),
1479 ("ecrecover(bytes32, uint8, bytes32, bytes32)", Address),
1480 ("addmod(uint, uint, uint)", Uint(256)),
1481 ("mulmod(uint, uint, uint)", Uint(256)),
1482 ("address(_)", Address),
1486 ("address(this)", Address),
1487 ("address.balance", Uint(256)),
1490 ("address.code", Bytes),
1491 ("address.codehash", FixedBytes(32)),
1492 ("address.send(uint256)", Bool),
1493 ("type(C).name", String),
1498 ("type(C).creationCode", Bytes),
1499 ("type(C).runtimeCode", Bytes),
1500 ("type(I).interfaceId", FixedBytes(4)),
1501 ("type(uint256).min", Uint(256)),
1502 ("type(int128).min", Int(128)),
1503 ("type(int256).min", Int(256)),
1504 ("type(uint256).max", Uint(256)),
1505 ("type(int128).max", Int(128)),
1506 ("type(int256).max", Int(256)),
1507 ("type(Enum1).min", Uint(256)),
1508 ("type(Enum1).max", Uint(256)),
1509 ("this.run.address", Address),
1511 ("this.run.selector", FixedBytes(4)),
1512 ]
1513 };
1514
1515 generic_type_test(&mut source(), global_variables);
1516 }
1517
1518 #[track_caller]
1519 fn source() -> SessionSource {
1520 static PRE_INSTALL_SOLC_LOCK: Mutex<bool> = Mutex::new(false);
1522
1523 let version = "0.8.20";
1526 for _ in 0..3 {
1527 let mut is_preinstalled = PRE_INSTALL_SOLC_LOCK.lock().unwrap();
1528 if !*is_preinstalled {
1529 let solc = Solc::find_or_install(&version.parse().unwrap())
1530 .map(|solc| (solc.version.clone(), solc));
1531 match solc {
1532 Ok((v, solc)) => {
1533 let _ = sh_println!("found installed Solc v{v} @ {}", solc.solc.display());
1535 break;
1536 }
1537 Err(e) => {
1538 let _ = sh_err!("error while trying to re-install Solc v{version}: {e}");
1540 let solc = Solc::blocking_install(&version.parse().unwrap());
1541 if solc.map_err(SolcError::from).is_ok() {
1542 *is_preinstalled = true;
1543 break;
1544 }
1545 }
1546 }
1547 }
1548 }
1549
1550 SessionSource::new(Default::default()).unwrap()
1551 }
1552
1553 fn array(ty: DynSolType) -> DynSolType {
1554 DynSolType::Array(Box::new(ty))
1555 }
1556
1557 fn fixed_array(ty: DynSolType, len: usize) -> DynSolType {
1558 DynSolType::FixedArray(Box::new(ty), len)
1559 }
1560
1561 fn parse(s: &mut SessionSource, input: &str, clear: bool) -> IntermediateOutput {
1562 if clear {
1563 s.clear();
1564 }
1565
1566 *s = s.clone_with_new_line("enum Enum1 { A }".into()).unwrap().0;
1567
1568 let input = format!("{};", input.trim_end().trim_end_matches(';'));
1569 let (mut _s, _) = s.clone_with_new_line(input).unwrap();
1570 *s = _s.clone();
1571 let s = &mut _s;
1572
1573 if let Err(e) = s.parse() {
1574 let source = s.to_repl_source();
1575 panic!("{e}\n\ncould not parse input:\n{source}")
1576 }
1577 s.generate_intermediate_output().expect("could not generate intermediate output")
1578 }
1579
1580 fn expr(stmts: &[pt::Statement]) -> pt::Expression {
1581 match stmts.last().expect("no statements") {
1582 pt::Statement::Expression(_, e) => e.clone(),
1583 s => panic!("Not an expression: {s:?}"),
1584 }
1585 }
1586
1587 fn get_type(
1588 s: &mut SessionSource,
1589 input: &str,
1590 clear: bool,
1591 ) -> (Option<Type>, IntermediateOutput) {
1592 let intermediate = parse(s, input, clear);
1593 let run_func_body = intermediate.run_func_body().expect("no run func body");
1594 let expr = expr(run_func_body);
1595 (Type::from_expression(&expr).map(Type::map_special), intermediate)
1596 }
1597
1598 fn get_type_ethabi(s: &mut SessionSource, input: &str, clear: bool) -> Option<DynSolType> {
1599 let (ty, intermediate) = get_type(s, input, clear);
1600 ty.and_then(|ty| ty.try_as_ethabi(Some(&intermediate)))
1601 }
1602
1603 fn generic_type_test<'a, T, I>(s: &mut SessionSource, input: I)
1604 where
1605 T: AsRef<str> + std::fmt::Display + 'a,
1606 I: IntoIterator<Item = &'a (T, DynSolType)> + 'a,
1607 {
1608 for (input, expected) in input {
1609 let input = input.as_ref();
1610 let ty = get_type_ethabi(s, input, true);
1611 assert_eq!(ty.as_ref(), Some(expected), "\n{input}");
1612 }
1613 }
1614
1615 fn init_tracing() {
1616 let _ = tracing_subscriber::FmtSubscriber::builder()
1617 .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
1618 .try_init();
1619 }
1620}