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
40 let Some(final_pc) = final_pc else { return Ok(Default::default()) };
41
42 let mut runner = self.build_runner(final_pc).await?;
43 runner.run(bytecode)
44 }
45
46 pub async fn inspect(&self, input: &str) -> Result<(ControlFlow<()>, Option<String>)> {
58 let line = format!("bytes memory inspectoor = abi.encode({input});");
59 let mut source = match self.clone_with_new_line(line) {
60 Ok((source, _)) => source,
61 Err(err) => {
62 debug!(%err, "failed to build new source");
63 return Ok((ControlFlow::Continue(()), None));
64 }
65 };
66
67 let mut source_without_inspector = self.clone();
68
69 let (mut res, err) = match source.execute().await {
72 Ok(res) => (res, None),
73 Err(err) => {
74 debug!(?err, %input, "execution failed");
75 match source_without_inspector.execute().await {
76 Ok(res) => (res, Some(err)),
77 Err(_) => {
78 if self.config.foundry_config.verbosity >= 3 {
79 sh_err!("Could not inspect: {err}")?;
80 }
81 return Ok((ControlFlow::Continue(()), None));
82 }
83 }
84 }
85 };
86
87 if let Some(err) = err {
89 let output = source_without_inspector.build()?;
90
91 let formatted_event =
92 output.enter(|output| output.get_event(input).map(format_event_definition));
93 if let Some(formatted_event) = formatted_event {
94 return Ok((ControlFlow::Break(()), Some(formatted_event?)));
95 }
96
97 if self.config.foundry_config.verbosity >= 3 {
99 sh_err!("Failed eval: {err}")?;
100 }
101
102 debug!(%err, %input, "failed abi encode input");
103 return Ok((ControlFlow::Break(()), None));
104 }
105 drop(source_without_inspector);
106
107 let Some((stack, memory)) = &res.state else {
108 if let Ok(decoder) = ChiselDispatcher::decode_traces(&source.config, &mut res).await {
110 ChiselDispatcher::show_traces(&decoder, &mut res).await?;
111 }
112 let decoded_logs = decode_console_logs(&res.logs);
113 if !decoded_logs.is_empty() {
114 sh_println!("{}", "Logs:".green())?;
115 for log in decoded_logs {
116 sh_println!(" {log}")?;
117 }
118 }
119
120 return Err(eyre::eyre!("Failed to inspect expression"));
121 };
122
123 let generated_output = source.build()?;
126
127 let contract_expr = generated_output
130 .intermediate
131 .repl_contract_expressions
132 .get(input)
133 .or_else(|| source.infer_inner_expr_type());
134
135 let function_call_return_type =
138 Type::get_function_return_type(contract_expr, &generated_output.intermediate);
139
140 let (contract_expr, ty) = if let Some(function_call_return_type) = function_call_return_type
141 {
142 (function_call_return_type.0, function_call_return_type.1)
143 } else {
144 match contract_expr.and_then(|e| {
145 Type::ethabi(e, Some(&generated_output.intermediate)).map(|ty| (e, ty))
146 }) {
147 Some(res) => res,
148 None => return Ok((ControlFlow::Continue(()), None)),
150 }
151 };
152
153 let mut offset = stack.last().unwrap().to::<usize>();
156 let mem_offset = &memory[offset..offset + 32];
157 let len = U256::try_from_be_slice(mem_offset).unwrap().to::<usize>();
158 offset += 32;
159 let data = &memory[offset..offset + len];
160 let token = ty.abi_decode(data).wrap_err("Could not decode inspected values")?;
161 let c = if should_continue(contract_expr) {
162 ControlFlow::Continue(())
163 } else {
164 ControlFlow::Break(())
165 };
166 Ok((c, Some(format_token(token))))
167 }
168
169 fn infer_inner_expr_type(&self) -> Option<&pt::Expression> {
180 let out = self.build().ok()?;
181 let run = out.run_func_body().ok()?.last();
182 match run {
183 Some(pt::Statement::VariableDefinition(
184 _,
185 _,
186 Some(pt::Expression::FunctionCall(_, _, args)),
187 )) => {
188 Some(args.first().unwrap())
192 }
193 _ => None,
194 }
195 }
196
197 async fn build_runner(&mut self, final_pc: usize) -> Result<ChiselRunner> {
198 let env = self.config.evm_opts.evm_env().await?;
199
200 let backend = match self.config.backend.clone() {
201 Some(backend) => backend,
202 None => {
203 let fork = self.config.evm_opts.get_fork(&self.config.foundry_config, env.clone());
204 let backend = Backend::spawn(fork)?;
205 self.config.backend = Some(backend.clone());
206 backend
207 }
208 };
209
210 let executor = ExecutorBuilder::new()
211 .inspectors(|stack| {
212 stack.chisel_state(final_pc).trace_mode(TraceMode::Call).cheatcodes(
213 CheatsConfig::new(
214 &self.config.foundry_config,
215 self.config.evm_opts.clone(),
216 None,
217 None,
218 )
219 .into(),
220 )
221 })
222 .gas_limit(self.config.evm_opts.gas_limit())
223 .spec_id(self.config.foundry_config.evm_spec_id())
224 .legacy_assertions(self.config.foundry_config.legacy_assertions)
225 .build(env, backend);
226
227 Ok(ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone()))
228 }
229}
230
231fn format_token(token: DynSolValue) -> String {
234 match token {
235 DynSolValue::Address(a) => {
236 format!("Type: {}\n└ Data: {}", "address".red(), a.cyan())
237 }
238 DynSolValue::FixedBytes(b, byte_len) => {
239 format!(
240 "Type: {}\n└ Data: {}",
241 format!("bytes{byte_len}").red(),
242 hex::encode_prefixed(b).cyan()
243 )
244 }
245 DynSolValue::Int(i, bit_len) => {
246 format!(
247 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
248 format!("int{bit_len}").red(),
249 format!(
250 "0x{}",
251 format!("{i:x}")
252 .char_indices()
253 .skip(64 - bit_len / 4)
254 .take(bit_len / 4)
255 .map(|(_, c)| c)
256 .collect::<String>()
257 )
258 .cyan(),
259 hex::encode_prefixed(B256::from(i)).cyan(),
260 i.cyan()
261 )
262 }
263 DynSolValue::Uint(i, bit_len) => {
264 format!(
265 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
266 format!("uint{bit_len}").red(),
267 format!(
268 "0x{}",
269 format!("{i:x}")
270 .char_indices()
271 .skip(64 - bit_len / 4)
272 .take(bit_len / 4)
273 .map(|(_, c)| c)
274 .collect::<String>()
275 )
276 .cyan(),
277 hex::encode_prefixed(B256::from(i)).cyan(),
278 i.cyan()
279 )
280 }
281 DynSolValue::Bool(b) => {
282 format!("Type: {}\n└ Value: {}", "bool".red(), b.cyan())
283 }
284 DynSolValue::String(_) | DynSolValue::Bytes(_) => {
285 let hex = hex::encode(token.abi_encode());
286 let s = token.as_str();
287 format!(
288 "Type: {}\n{}├ Hex (Memory):\n├─ Length ({}): {}\n├─ Contents ({}): {}\n├ Hex (Tuple Encoded):\n├─ Pointer ({}): {}\n├─ Length ({}): {}\n└─ Contents ({}): {}",
289 if s.is_some() { "string" } else { "dynamic bytes" }.red(),
290 if let Some(s) = s {
291 format!("├ UTF-8: {}\n", s.cyan())
292 } else {
293 String::default()
294 },
295 "[0x00:0x20]".yellow(),
296 format!("0x{}", &hex[64..128]).cyan(),
297 "[0x20:..]".yellow(),
298 format!("0x{}", &hex[128..]).cyan(),
299 "[0x00:0x20]".yellow(),
300 format!("0x{}", &hex[..64]).cyan(),
301 "[0x20:0x40]".yellow(),
302 format!("0x{}", &hex[64..128]).cyan(),
303 "[0x40:..]".yellow(),
304 format!("0x{}", &hex[128..]).cyan(),
305 )
306 }
307 DynSolValue::FixedArray(tokens) | DynSolValue::Array(tokens) => {
308 let mut out = format!(
309 "{}({}) = {}",
310 "array".red(),
311 format!("{}", tokens.len()).yellow(),
312 '['.red()
313 );
314 for token in tokens {
315 out.push_str("\n ├ ");
316 out.push_str(&format_token(token).replace('\n', "\n "));
317 out.push('\n');
318 }
319 out.push_str(&']'.red().to_string());
320 out
321 }
322 DynSolValue::Tuple(tokens) => {
323 let displayed_types = tokens
324 .iter()
325 .map(|t| t.sol_type_name().unwrap_or_default())
326 .collect::<Vec<_>>()
327 .join(", ");
328 let mut out =
329 format!("{}({}) = {}", "tuple".red(), displayed_types.yellow(), '('.red());
330 for token in tokens {
331 out.push_str("\n ├ ");
332 out.push_str(&format_token(token).replace('\n', "\n "));
333 out.push('\n');
334 }
335 out.push_str(&')'.red().to_string());
336 out
337 }
338 _ => {
339 unimplemented!()
340 }
341 }
342}
343
344fn format_event_definition(event_definition: &pt::EventDefinition) -> Result<String> {
355 let event_name = event_definition.name.as_ref().expect("Event has a name").to_string();
356 let inputs = event_definition
357 .fields
358 .iter()
359 .map(|param| {
360 let name = param
361 .name
362 .as_ref()
363 .map(ToString::to_string)
364 .unwrap_or_else(|| "<anonymous>".to_string());
365 let kind = Type::from_expression(¶m.ty)
366 .and_then(Type::into_builtin)
367 .ok_or_else(|| eyre::eyre!("Invalid type in event {event_name}"))?;
368 Ok(EventParam {
369 name,
370 ty: kind.to_string(),
371 components: vec![],
372 indexed: param.indexed,
373 internal_type: None,
374 })
375 })
376 .collect::<Result<Vec<_>>>()?;
377 let event =
378 alloy_json_abi::Event { name: event_name, inputs, anonymous: event_definition.anonymous };
379
380 Ok(format!(
381 "Type: {}\n├ Name: {}\n├ Signature: {:?}\n└ Selector: {:?}",
382 "event".red(),
383 SolidityHelper::new().highlight(&format!(
384 "{}({})",
385 &event.name,
386 &event
387 .inputs
388 .iter()
389 .map(|param| format!(
390 "{}{}{}",
391 param.ty,
392 if param.indexed { " indexed" } else { "" },
393 if param.name.is_empty() {
394 String::default()
395 } else {
396 format!(" {}", ¶m.name)
397 },
398 ))
399 .collect::<Vec<_>>()
400 .join(", ")
401 )),
402 event.signature().cyan(),
403 event.selector().cyan(),
404 ))
405}
406
407#[derive(Clone, Debug, PartialEq)]
413enum Type {
414 Builtin(DynSolType),
416
417 Array(Box<Type>),
419
420 FixedArray(Box<Type>, usize),
422
423 ArrayIndex(Box<Type>, Option<usize>),
425
426 Tuple(Vec<Option<Type>>),
428
429 Function(Box<Type>, Vec<Option<Type>>, Vec<Option<Type>>),
431
432 Access(Box<Type>, String),
434
435 Custom(Vec<String>),
437}
438
439impl Type {
440 fn from_expression(expr: &pt::Expression) -> Option<Self> {
450 match expr {
451 pt::Expression::Type(_, ty) => Self::from_type(ty),
452
453 pt::Expression::Variable(ident) => Some(Self::Custom(vec![ident.name.clone()])),
454
455 pt::Expression::ArraySubscript(_, expr, num) => {
457 Self::from_expression(expr).and_then(|ty| {
460 let boxed = Box::new(ty);
461 let num = num.as_deref().and_then(parse_number_literal).and_then(|n| {
462 usize::try_from(n).ok()
463 });
464 match expr.as_ref() {
465 pt::Expression::Type(_, _) => {
467 if let Some(num) = num {
468 Some(Self::FixedArray(boxed, num))
469 } else {
470 Some(Self::Array(boxed))
471 }
472 }
473 pt::Expression::Variable(_) => {
475 Some(Self::ArrayIndex(boxed, num))
476 }
477 _ => None
478 }
479 })
480 }
481 pt::Expression::ArrayLiteral(_, values) => {
482 values.first().and_then(Self::from_expression).map(|ty| {
483 Self::FixedArray(Box::new(ty), values.len())
484 })
485 }
486
487 pt::Expression::List(_, params) => Some(Self::Tuple(map_parameters(params))),
489
490 pt::Expression::MemberAccess(_, lhs, rhs) => {
492 Self::from_expression(lhs).map(|lhs| {
493 Self::Access(Box::new(lhs), rhs.name.clone())
494 })
495 }
496
497 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),
521
522 pt::Expression::ConditionalOperator(_, _, if_true, if_false) => {
524 Self::from_expression(if_true).or_else(|| Self::from_expression(if_false))
525 }
526
527 pt::Expression::AddressLiteral(_, _) => Some(Self::Builtin(DynSolType::Address)),
529 pt::Expression::HexNumberLiteral(_, s, _) => {
530 match s.parse::<Address>() {
531 Ok(addr) => {
532 if *s == addr.to_checksum(None) {
533 Some(Self::Builtin(DynSolType::Address))
534 } else {
535 Some(Self::Builtin(DynSolType::Uint(256)))
536 }
537 },
538 _ => {
539 Some(Self::Builtin(DynSolType::Uint(256)))
540 }
541 }
542 }
543
544 pt::Expression::Negate(_, inner) => Self::from_expression(inner).map(Self::invert_int),
547
548 pt::Expression::Add(_, lhs, rhs) |
552 pt::Expression::Subtract(_, lhs, rhs) |
553 pt::Expression::Multiply(_, lhs, rhs) |
554 pt::Expression::Divide(_, lhs, rhs) => {
555 match (Self::ethabi(lhs, None), Self::ethabi(rhs, None)) {
556 (Some(DynSolType::Int(_)), Some(DynSolType::Int(_))) |
557 (Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) |
558 (Some(DynSolType::Uint(_)), Some(DynSolType::Int(_))) => {
559 Some(Self::Builtin(DynSolType::Int(256)))
560 }
561 _ => {
562 Some(Self::Builtin(DynSolType::Uint(256)))
563 }
564 }
565 }
566
567 pt::Expression::Modulo(_, _, _) |
569 pt::Expression::Power(_, _, _) |
570 pt::Expression::BitwiseOr(_, _, _) |
571 pt::Expression::BitwiseAnd(_, _, _) |
572 pt::Expression::BitwiseXor(_, _, _) |
573 pt::Expression::ShiftRight(_, _, _) |
574 pt::Expression::ShiftLeft(_, _, _) |
575 pt::Expression::NumberLiteral(_, _, _, _) => Some(Self::Builtin(DynSolType::Uint(256))),
576
577 pt::Expression::RationalNumberLiteral(_, _, _, _, _) => {
579 Some(Self::Builtin(DynSolType::Uint(256)))
580 }
581
582 pt::Expression::BoolLiteral(_, _) |
584 pt::Expression::And(_, _, _) |
585 pt::Expression::Or(_, _, _) |
586 pt::Expression::Equal(_, _, _) |
587 pt::Expression::NotEqual(_, _, _) |
588 pt::Expression::Less(_, _, _) |
589 pt::Expression::LessEqual(_, _, _) |
590 pt::Expression::More(_, _, _) |
591 pt::Expression::MoreEqual(_, _, _) |
592 pt::Expression::Not(_, _) => Some(Self::Builtin(DynSolType::Bool)),
593
594 pt::Expression::StringLiteral(_) => Some(Self::Builtin(DynSolType::String)),
596
597 pt::Expression::HexLiteral(_) => Some(Self::Builtin(DynSolType::Bytes)),
599
600 pt::Expression::FunctionCall(_, name, args) => {
602 Self::from_expression(name).map(|name| {
603 let args = args.iter().map(Self::from_expression).collect();
604 Self::Function(Box::new(name), args, vec![])
605 })
606 }
607 pt::Expression::NamedFunctionCall(_, name, args) => {
608 Self::from_expression(name).map(|name| {
609 let args = args.iter().map(|arg| Self::from_expression(&arg.expr)).collect();
610 Self::Function(Box::new(name), args, vec![])
611 })
612 }
613
614 pt::Expression::Delete(_, _) | pt::Expression::FunctionCallBlock(_, _, _) => None,
616 }
617 }
618
619 fn from_type(ty: &pt::Type) -> Option<Self> {
629 let ty = match ty {
630 pt::Type::Address | pt::Type::AddressPayable | pt::Type::Payable => {
631 Self::Builtin(DynSolType::Address)
632 }
633 pt::Type::Bool => Self::Builtin(DynSolType::Bool),
634 pt::Type::String => Self::Builtin(DynSolType::String),
635 pt::Type::Int(size) => Self::Builtin(DynSolType::Int(*size as usize)),
636 pt::Type::Uint(size) => Self::Builtin(DynSolType::Uint(*size as usize)),
637 pt::Type::Bytes(size) => Self::Builtin(DynSolType::FixedBytes(*size as usize)),
638 pt::Type::DynamicBytes => Self::Builtin(DynSolType::Bytes),
639 pt::Type::Mapping { value, .. } => Self::from_expression(value)?,
640 pt::Type::Function { params, returns, .. } => {
641 let params = map_parameters(params);
642 let returns = returns
643 .as_ref()
644 .map(|(returns, _)| map_parameters(returns))
645 .unwrap_or_default();
646 Self::Function(
647 Box::new(Self::Custom(vec!["__fn_type__".to_string()])),
648 params,
649 returns,
650 )
651 }
652 pt::Type::Rational => return None,
654 };
655 Some(ty)
656 }
657
658 fn map_special(self) -> Self {
662 if !matches!(self, Self::Function(_, _, _) | Self::Access(_, _) | Self::Custom(_)) {
663 return self;
664 }
665
666 let mut types = Vec::with_capacity(5);
667 let mut args = None;
668 self.recurse(&mut types, &mut args);
669
670 let len = types.len();
671 if len == 0 {
672 return self;
673 }
674
675 #[expect(clippy::single_match)]
677 match &self {
678 Self::Access(inner, access) => {
679 if let Some(ty) = inner.as_ref().clone().try_as_ethabi(None) {
680 let ty = Self::Builtin(ty);
682 match access.as_str() {
683 "length" if ty.is_dynamic() || ty.is_array() || ty.is_fixed_bytes() => {
684 return Self::Builtin(DynSolType::Uint(256));
685 }
686 "pop" if ty.is_dynamic_array() => return ty,
687 _ => {}
688 }
689 }
690 }
691 _ => {}
692 }
693
694 let this = {
695 let name = types.last().unwrap().as_str();
696 match len {
697 0 => unreachable!(),
698 1 => match name {
699 "gasleft" | "addmod" | "mulmod" => Some(DynSolType::Uint(256)),
700 "keccak256" | "sha256" | "blockhash" => Some(DynSolType::FixedBytes(32)),
701 "ripemd160" => Some(DynSolType::FixedBytes(20)),
702 "ecrecover" => Some(DynSolType::Address),
703 _ => None,
704 },
705 2 => {
706 let access = types.first().unwrap().as_str();
707 match name {
708 "block" => match access {
709 "coinbase" => Some(DynSolType::Address),
710 "timestamp" | "difficulty" | "prevrandao" | "number" | "gaslimit"
711 | "chainid" | "basefee" | "blobbasefee" => Some(DynSolType::Uint(256)),
712 _ => None,
713 },
714 "msg" => match access {
715 "sender" => Some(DynSolType::Address),
716 "gas" => Some(DynSolType::Uint(256)),
717 "value" => Some(DynSolType::Uint(256)),
718 "data" => Some(DynSolType::Bytes),
719 "sig" => Some(DynSolType::FixedBytes(4)),
720 _ => None,
721 },
722 "tx" => match access {
723 "origin" => Some(DynSolType::Address),
724 "gasprice" => Some(DynSolType::Uint(256)),
725 _ => None,
726 },
727 "abi" => match access {
728 "decode" => {
729 let mut args = args.unwrap();
733 let last = args.pop().unwrap();
734 match last {
735 Some(ty) => {
736 return match ty {
737 Self::Tuple(_) => ty,
738 ty => Self::Tuple(vec![Some(ty)]),
739 };
740 }
741 None => None,
742 }
743 }
744 s if s.starts_with("encode") => Some(DynSolType::Bytes),
745 _ => None,
746 },
747 "address" => match access {
748 "balance" => Some(DynSolType::Uint(256)),
749 "code" => Some(DynSolType::Bytes),
750 "codehash" => Some(DynSolType::FixedBytes(32)),
751 "send" => Some(DynSolType::Bool),
752 _ => None,
753 },
754 "type" => match access {
755 "name" => Some(DynSolType::String),
756 "creationCode" | "runtimeCode" => Some(DynSolType::Bytes),
757 "interfaceId" => Some(DynSolType::FixedBytes(4)),
758 "min" | "max" => Some(
759 (|| args?.pop()??.into_builtin())()
761 .unwrap_or(DynSolType::Uint(256)),
762 ),
763 _ => None,
764 },
765 "string" => match access {
766 "concat" => Some(DynSolType::String),
767 _ => None,
768 },
769 "bytes" => match access {
770 "concat" => Some(DynSolType::Bytes),
771 _ => None,
772 },
773 _ => None,
774 }
775 }
776 _ => None,
777 }
778 };
779
780 this.map(Self::Builtin).unwrap_or_else(|| match types.last().unwrap().as_str() {
781 "this" | "super" => Self::Custom(types),
782 _ => match self {
783 Self::Custom(_) | Self::Access(_, _) => Self::Custom(types),
784 Self::Function(_, _, _) => self,
785 _ => unreachable!(),
786 },
787 })
788 }
789
790 fn recurse(&self, types: &mut Vec<String>, args: &mut Option<Vec<Option<Self>>>) {
793 match self {
794 Self::Builtin(ty) => types.push(ty.to_string()),
795 Self::Custom(tys) => types.extend(tys.clone()),
796 Self::Access(expr, name) => {
797 types.push(name.clone());
798 expr.recurse(types, args);
799 }
800 Self::Function(fn_name, fn_args, _fn_ret) => {
801 if args.is_none() && !fn_args.is_empty() {
802 *args = Some(fn_args.clone());
803 }
804 fn_name.recurse(types, args);
805 }
806 _ => {}
807 }
808 }
809
810 fn infer_custom_type(
824 intermediate: &IntermediateOutput,
825 custom_type: &mut Vec<String>,
826 contract_name: Option<String>,
827 ) -> Result<Option<DynSolType>> {
828 if let Some("this") | Some("super") = custom_type.last().map(String::as_str) {
829 custom_type.pop();
830 }
831 if custom_type.is_empty() {
832 return Ok(None);
833 }
834
835 if let Some(contract_name) = contract_name {
838 let intermediate_contract = intermediate
839 .intermediate_contracts
840 .get(&contract_name)
841 .ok_or_else(|| eyre::eyre!("Could not find intermediate contract!"))?;
842
843 let cur_type = custom_type.last().unwrap();
844 if let Some(func) = intermediate_contract.function_definitions.get(cur_type) {
845 if let res @ Some(_) = func_members(func, custom_type) {
847 return Ok(res);
848 }
849
850 if func.returns.is_empty() {
853 eyre::bail!(
854 "This call expression does not return any values to inspect. Insert as statement."
855 )
856 }
857
858 let (_, param) = func.returns.first().unwrap();
860 let return_ty = ¶m.as_ref().unwrap().ty;
862
863 if let pt::Expression::Variable(ident) = return_ty {
867 custom_type.push(ident.name.clone());
868 return Self::infer_custom_type(intermediate, custom_type, Some(contract_name));
869 }
870
871 if let Some(pt::FunctionAttribute::Mutability(_mut)) = func
875 .attributes
876 .iter()
877 .find(|attr| matches!(attr, pt::FunctionAttribute::Mutability(_)))
878 {
879 if let pt::Mutability::Payable(_) = _mut {
880 eyre::bail!("This function mutates state. Insert as a statement.")
881 }
882 } else {
883 eyre::bail!("This function mutates state. Insert as a statement.")
884 }
885
886 Ok(Self::ethabi(return_ty, Some(intermediate)))
887 } else if let Some(var) = intermediate_contract.variable_definitions.get(cur_type) {
888 Self::infer_var_expr(&var.ty, Some(intermediate), custom_type)
889 } else if let Some(strukt) = intermediate_contract.struct_definitions.get(cur_type) {
890 let inner_types = strukt
891 .fields
892 .iter()
893 .map(|var| {
894 Self::ethabi(&var.ty, Some(intermediate))
895 .ok_or_else(|| eyre::eyre!("Struct `{cur_type}` has invalid fields"))
896 })
897 .collect::<Result<Vec<_>>>()?;
898 Ok(Some(DynSolType::Tuple(inner_types)))
899 } else {
900 eyre::bail!(
901 "Could not find any definition in contract \"{contract_name}\" for type: {custom_type:?}"
902 )
903 }
904 } else {
905 if let Ok(res) = Self::infer_custom_type(intermediate, custom_type, Some("REPL".into()))
908 {
909 return Ok(res);
910 }
911
912 let name = custom_type.last().unwrap();
915 let contract = intermediate.intermediate_contracts.get(name);
916 if contract.is_some() {
917 let contract_name = custom_type.pop();
918 return Self::infer_custom_type(intermediate, custom_type, contract_name);
919 }
920
921 let name = custom_type.last().unwrap();
923 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
924 return Self::infer_var_expr(expr, Some(intermediate), custom_type);
925 }
926
927 Ok(None)
930 }
931 }
932
933 fn infer_var_expr(
935 expr: &pt::Expression,
936 intermediate: Option<&IntermediateOutput>,
937 custom_type: &mut Vec<String>,
938 ) -> Result<Option<DynSolType>> {
939 let res = match &expr {
941 pt::Expression::Variable(ident) => {
943 let name = &ident.name;
944
945 if let Some(intermediate) = intermediate {
946 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
948 Self::infer_var_expr(expr, Some(intermediate), custom_type)
949 } else if intermediate.intermediate_contracts.contains_key(name) {
950 if custom_type.len() > 1 {
951 custom_type.pop();
953 Self::infer_custom_type(intermediate, custom_type, Some(name.clone()))
954 } else {
955 Ok(Some(DynSolType::Address))
957 }
958 } else {
959 Err(eyre::eyre!("Could not infer variable type"))
960 }
961 } else {
962 Ok(None)
963 }
964 }
965 ty => Ok(Self::ethabi(ty, intermediate)),
966 };
967 match res {
970 Ok(Some(ty)) => {
971 let box_ty = Box::new(Self::Builtin(ty.clone()));
972 let access = Self::Access(box_ty, custom_type.drain(..).next().unwrap_or_default());
973 if let Some(mapped) = access.map_special().try_as_ethabi(intermediate) {
974 Ok(Some(mapped))
975 } else {
976 Ok(Some(ty))
977 }
978 }
979 res => res,
980 }
981 }
982
983 fn try_as_ethabi(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
991 match self {
992 Self::Builtin(ty) => Some(ty),
993 Self::Tuple(types) => Some(DynSolType::Tuple(types_to_parameters(types, intermediate))),
994 Self::Array(inner) => match *inner {
995 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
996 _ => inner
997 .try_as_ethabi(intermediate)
998 .map(|inner| DynSolType::Array(Box::new(inner))),
999 },
1000 Self::FixedArray(inner, size) => match *inner {
1001 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
1002 _ => inner
1003 .try_as_ethabi(intermediate)
1004 .map(|inner| DynSolType::FixedArray(Box::new(inner), size)),
1005 },
1006 ty @ Self::ArrayIndex(_, _) => ty.into_array_index(intermediate),
1007 Self::Function(ty, _, _) => ty.try_as_ethabi(intermediate),
1008 Self::Access(_, _) => None,
1010 Self::Custom(mut types) => {
1011 intermediate.and_then(|intermediate| {
1013 Self::infer_custom_type(intermediate, &mut types, None).ok().flatten()
1014 })
1015 }
1016 }
1017 }
1018
1019 fn ethabi(
1021 expr: &pt::Expression,
1022 intermediate: Option<&IntermediateOutput>,
1023 ) -> Option<DynSolType> {
1024 Self::from_expression(expr)
1025 .map(Self::map_special)
1026 .and_then(|ty| ty.try_as_ethabi(intermediate))
1027 }
1028
1029 fn get_function_return_type<'a>(
1031 contract_expr: Option<&'a pt::Expression>,
1032 intermediate: &IntermediateOutput,
1033 ) -> Option<(&'a pt::Expression, DynSolType)> {
1034 let function_call = match contract_expr? {
1035 pt::Expression::FunctionCall(_, function_call, _) => function_call,
1036 _ => return None,
1037 };
1038 let (contract_name, function_name) = match function_call.as_ref() {
1039 pt::Expression::MemberAccess(_, contract_name, function_name) => {
1040 (contract_name, function_name)
1041 }
1042 _ => return None,
1043 };
1044 let contract_name = match contract_name.as_ref() {
1045 pt::Expression::Variable(contract_name) => contract_name.to_owned(),
1046 _ => return None,
1047 };
1048
1049 let pt::Expression::Variable(contract_name) =
1050 intermediate.repl_contract_expressions.get(&contract_name.name)?
1051 else {
1052 return None;
1053 };
1054
1055 let contract = intermediate
1056 .intermediate_contracts
1057 .get(&contract_name.name)?
1058 .function_definitions
1059 .get(&function_name.name)?;
1060 let return_parameter = contract.as_ref().returns.first()?.to_owned().1?;
1061 Self::ethabi(&return_parameter.ty, Some(intermediate)).map(|p| (contract_expr.unwrap(), p))
1062 }
1063
1064 fn invert_int(self) -> Self {
1066 match self {
1067 Self::Builtin(DynSolType::Uint(n)) => Self::Builtin(DynSolType::Int(n)),
1068 Self::Builtin(DynSolType::Int(n)) => Self::Builtin(DynSolType::Uint(n)),
1069 x => x,
1070 }
1071 }
1072
1073 #[inline]
1075 fn into_builtin(self) -> Option<DynSolType> {
1076 match self {
1077 Self::Builtin(ty) => Some(ty),
1078 _ => None,
1079 }
1080 }
1081
1082 fn into_array_index(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
1084 match self {
1085 Self::Array(inner) | Self::FixedArray(inner, _) | Self::ArrayIndex(inner, _) => {
1086 match inner.try_as_ethabi(intermediate) {
1087 Some(DynSolType::Array(inner)) | Some(DynSolType::FixedArray(inner, _)) => {
1088 Some(*inner)
1089 }
1090 Some(DynSolType::Bytes)
1091 | Some(DynSolType::String)
1092 | Some(DynSolType::FixedBytes(_)) => Some(DynSolType::FixedBytes(1)),
1093 ty => ty,
1094 }
1095 }
1096 _ => None,
1097 }
1098 }
1099
1100 #[inline]
1102 fn is_dynamic(&self) -> bool {
1103 match self {
1104 Self::Builtin(DynSolType::Bytes | DynSolType::String | DynSolType::Array(_)) => true,
1107 Self::Array(_) => true,
1108 _ => false,
1109 }
1110 }
1111
1112 #[inline]
1114 fn is_array(&self) -> bool {
1115 matches!(
1116 self,
1117 Self::Array(_)
1118 | Self::FixedArray(_, _)
1119 | Self::Builtin(DynSolType::Array(_))
1120 | Self::Builtin(DynSolType::FixedArray(_, _))
1121 )
1122 }
1123
1124 #[inline]
1126 fn is_dynamic_array(&self) -> bool {
1127 matches!(self, Self::Array(_) | Self::Builtin(DynSolType::Array(_)))
1128 }
1129
1130 fn is_fixed_bytes(&self) -> bool {
1131 matches!(self, Self::Builtin(DynSolType::FixedBytes(_)))
1132 }
1133}
1134
1135#[inline]
1139fn func_members(func: &pt::FunctionDefinition, custom_type: &[String]) -> Option<DynSolType> {
1140 if !matches!(func.ty, pt::FunctionTy::Function) {
1141 return None;
1142 }
1143
1144 let vis = func.attributes.iter().find_map(|attr| match attr {
1145 pt::FunctionAttribute::Visibility(vis) => Some(vis),
1146 _ => None,
1147 });
1148 match vis {
1149 Some(pt::Visibility::External(_)) | Some(pt::Visibility::Public(_)) => {
1150 match custom_type.first().unwrap().as_str() {
1151 "address" => Some(DynSolType::Address),
1152 "selector" => Some(DynSolType::FixedBytes(4)),
1153 _ => None,
1154 }
1155 }
1156 _ => None,
1157 }
1158}
1159
1160#[inline]
1162fn should_continue(expr: &pt::Expression) -> bool {
1163 match expr {
1164 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(_, _, _) => {
1181 true
1182 }
1183
1184 pt::Expression::FunctionCall(_, lhs, _) => {
1186 match lhs.as_ref() {
1187 pt::Expression::MemberAccess(_, _inner, access) => access.name == "pop",
1188 _ => false
1189 }
1190 }
1191
1192 _ => false
1193 }
1194}
1195
1196fn map_parameters(params: &[(pt::Loc, Option<pt::Parameter>)]) -> Vec<Option<Type>> {
1197 params
1198 .iter()
1199 .map(|(_, param)| param.as_ref().and_then(|param| Type::from_expression(¶m.ty)))
1200 .collect()
1201}
1202
1203fn types_to_parameters(
1204 types: Vec<Option<Type>>,
1205 intermediate: Option<&IntermediateOutput>,
1206) -> Vec<DynSolType> {
1207 types.into_iter().filter_map(|ty| ty.and_then(|ty| ty.try_as_ethabi(intermediate))).collect()
1208}
1209
1210fn parse_number_literal(expr: &pt::Expression) -> Option<U256> {
1211 match expr {
1212 pt::Expression::NumberLiteral(_, num, exp, unit) => {
1213 let num = num.parse::<U256>().unwrap_or(U256::ZERO);
1214 let exp = exp.parse().unwrap_or(0u32);
1215 if exp > 77 {
1216 None
1217 } else {
1218 let exp = U256::from(10usize.pow(exp));
1219 let unit_mul = unit_multiplier(unit).ok()?;
1220 Some(num * exp * unit_mul)
1221 }
1222 }
1223 pt::Expression::HexNumberLiteral(_, num, unit) => {
1224 let unit_mul = unit_multiplier(unit).ok()?;
1225 num.parse::<U256>().map(|num| num * unit_mul).ok()
1226 }
1227 pt::Expression::RationalNumberLiteral(..) => None,
1229 _ => None,
1230 }
1231}
1232
1233#[inline]
1234fn unit_multiplier(unit: &Option<pt::Identifier>) -> Result<U256> {
1235 if let Some(unit) = unit {
1236 let mul = match unit.name.as_str() {
1237 "seconds" => 1,
1238 "minutes" => 60,
1239 "hours" => 60 * 60,
1240 "days" => 60 * 60 * 24,
1241 "weeks" => 60 * 60 * 24 * 7,
1242 "wei" => 1,
1243 "gwei" => 10_usize.pow(9),
1244 "ether" => 10_usize.pow(18),
1245 other => eyre::bail!("unknown unit: {other}"),
1246 };
1247 Ok(U256::from(mul))
1248 } else {
1249 Ok(U256::from(1))
1250 }
1251}
1252
1253#[cfg(test)]
1254mod tests {
1255 use super::*;
1256 use foundry_compilers::{error::SolcError, solc::Solc};
1257 use std::sync::Mutex;
1258
1259 #[test]
1260 fn test_expressions() {
1261 static EXPRESSIONS: &[(&str, DynSolType)] = {
1262 use DynSolType::*;
1263 &[
1264 ("1 seconds", Uint(256)),
1267 ("1 minutes", Uint(256)),
1268 ("1 hours", Uint(256)),
1269 ("1 days", Uint(256)),
1270 ("1 weeks", Uint(256)),
1271 ("1 wei", Uint(256)),
1272 ("1 gwei", Uint(256)),
1273 ("1 ether", Uint(256)),
1274 ("-1 seconds", Int(256)),
1276 ("-1 minutes", Int(256)),
1277 ("-1 hours", Int(256)),
1278 ("-1 days", Int(256)),
1279 ("-1 weeks", Int(256)),
1280 ("-1 wei", Int(256)),
1281 ("-1 gwei", Int(256)),
1282 ("-1 ether", Int(256)),
1283 ("true ? 1 : 0", Uint(256)),
1285 ("true ? -1 : 0", Int(256)),
1286 ("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 ("1 | 1", Uint(256)),
1298 ("1 & 1", Uint(256)),
1299 ("1 ^ 1", Uint(256)),
1300 ("1 >> 1", Uint(256)),
1301 ("1 << 1", Uint(256)),
1302 ("int(1) + 1", Int(256)),
1304 ("int(1) - 1", Int(256)),
1305 ("int(1) * 1", Int(256)),
1306 ("int(1) / 1", Int(256)),
1307 ("1 + int(1)", Int(256)),
1308 ("1 - int(1)", Int(256)),
1309 ("1 * int(1)", Int(256)),
1310 ("1 / int(1)", Int(256)),
1311 ("uint256 a; a--", Uint(256)),
1315 ("uint256 a; --a", Uint(256)),
1316 ("uint256 a; a++", Uint(256)),
1317 ("uint256 a; ++a", 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 ("uint256 a; a &= 1", Uint(256)),
1325 ("uint256 a; a |= 1", Uint(256)),
1326 ("uint256 a; a ^= 1", Uint(256)),
1327 ("uint256 a; a <<= 1", Uint(256)),
1328 ("uint256 a; a >>= 1", Uint(256)),
1329 ("true && true", Bool),
1333 ("true || true", Bool),
1334 ("true == true", Bool),
1335 ("true != true", Bool),
1336 ("true < true", Bool),
1337 ("true <= true", Bool),
1338 ("true > true", Bool),
1339 ("true >= true", Bool),
1340 ("!true", Bool),
1341 ]
1343 };
1344
1345 let source = &mut source();
1346
1347 let array_expressions: &[(&str, DynSolType)] = &[
1348 ("[1, 2, 3]", fixed_array(DynSolType::Uint(256), 3)),
1349 ("[uint8(1), 2, 3]", fixed_array(DynSolType::Uint(8), 3)),
1350 ("[int8(1), 2, 3]", fixed_array(DynSolType::Int(8), 3)),
1351 ("new uint256[](3)", array(DynSolType::Uint(256))),
1352 ("uint256[] memory a = new uint256[](3);\na[0]", DynSolType::Uint(256)),
1353 ("uint256[] memory a = new uint256[](3);\na[0:3]", array(DynSolType::Uint(256))),
1354 ];
1355 generic_type_test(source, array_expressions);
1356 generic_type_test(source, EXPRESSIONS);
1357 }
1358
1359 #[test]
1360 fn test_types() {
1361 static TYPES: &[(&str, DynSolType)] = {
1362 use DynSolType::*;
1363 &[
1364 ("bool", Bool),
1366 ("true", Bool),
1367 ("false", Bool),
1368 ("uint", Uint(256)),
1372 ("uint(1)", Uint(256)),
1373 ("1", Uint(256)),
1374 ("0x01", Uint(256)),
1375 ("int", Int(256)),
1376 ("int(1)", Int(256)),
1377 ("int(-1)", Int(256)),
1378 ("-1", Int(256)),
1379 ("-0x01", Int(256)),
1380 ("address", Address),
1384 ("address(0)", Address),
1385 ("0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990", Address),
1386 ("payable(0)", Address),
1387 ("payable(address(0))", Address),
1388 ("string", String),
1392 ("string(\"hello world\")", String),
1393 ("\"hello world\"", String),
1394 ("unicode\"hello world 😀\"", String),
1395 ("bytes", Bytes),
1399 ("bytes(\"hello world\")", Bytes),
1400 ("bytes(unicode\"hello world 😀\")", Bytes),
1401 ("hex\"68656c6c6f20776f726c64\"", Bytes),
1402 ]
1404 };
1405
1406 let mut types: Vec<(String, DynSolType)> = Vec::with_capacity(96 + 32 + 100);
1407 for (n, b) in (8..=256).step_by(8).zip(1..=32) {
1408 types.push((format!("uint{n}(0)"), DynSolType::Uint(n)));
1409 types.push((format!("int{n}(0)"), DynSolType::Int(n)));
1410 types.push((format!("bytes{b}(0x00)"), DynSolType::FixedBytes(b)));
1411 }
1412
1413 for n in 0..=32 {
1414 types.push((
1415 format!("uint256[{n}]"),
1416 DynSolType::FixedArray(Box::new(DynSolType::Uint(256)), n),
1417 ));
1418 }
1419
1420 generic_type_test(&mut source(), TYPES);
1421 generic_type_test(&mut source(), &types);
1422 }
1423
1424 #[test]
1425 fn test_global_vars() {
1426 init_tracing();
1427
1428 let global_variables = {
1430 use DynSolType::*;
1431 &[
1432 ("abi.decode(bytes, (uint8[13]))", Tuple(vec![FixedArray(Box::new(Uint(8)), 13)])),
1434 ("abi.decode(bytes, (address, bytes))", Tuple(vec![Address, Bytes])),
1435 ("abi.decode(bytes, (uint112, uint48))", Tuple(vec![Uint(112), Uint(48)])),
1436 ("abi.encode(_, _)", Bytes),
1437 ("abi.encodePacked(_, _)", Bytes),
1438 ("abi.encodeWithSelector(bytes4, _, _)", Bytes),
1439 ("abi.encodeCall(func(), (_, _))", Bytes),
1440 ("abi.encodeWithSignature(string, _, _)", Bytes),
1441 ("bytes.concat()", Bytes),
1445 ("bytes.concat(_)", Bytes),
1446 ("bytes.concat(_, _)", Bytes),
1447 ("string.concat()", String),
1448 ("string.concat(_)", String),
1449 ("string.concat(_, _)", String),
1450 ("block.basefee", Uint(256)),
1454 ("block.chainid", Uint(256)),
1455 ("block.coinbase", Address),
1456 ("block.difficulty", Uint(256)),
1457 ("block.gaslimit", Uint(256)),
1458 ("block.number", Uint(256)),
1459 ("block.timestamp", Uint(256)),
1460 ("gasleft()", Uint(256)),
1464 ("msg.data", Bytes),
1465 ("msg.sender", Address),
1466 ("msg.sig", FixedBytes(4)),
1467 ("msg.value", Uint(256)),
1468 ("tx.gasprice", Uint(256)),
1469 ("tx.origin", Address),
1470 ("blockhash(uint)", FixedBytes(32)),
1481 ("keccak256(bytes)", FixedBytes(32)),
1482 ("sha256(bytes)", FixedBytes(32)),
1483 ("ripemd160(bytes)", FixedBytes(20)),
1484 ("ecrecover(bytes32, uint8, bytes32, bytes32)", Address),
1485 ("addmod(uint, uint, uint)", Uint(256)),
1486 ("mulmod(uint, uint, uint)", Uint(256)),
1487 ("address(_)", Address),
1491 ("address(this)", Address),
1492 ("address.balance", Uint(256)),
1495 ("address.code", Bytes),
1496 ("address.codehash", FixedBytes(32)),
1497 ("address.send(uint256)", Bool),
1498 ("type(C).name", String),
1503 ("type(C).creationCode", Bytes),
1504 ("type(C).runtimeCode", Bytes),
1505 ("type(I).interfaceId", FixedBytes(4)),
1506 ("type(uint256).min", Uint(256)),
1507 ("type(int128).min", Int(128)),
1508 ("type(int256).min", Int(256)),
1509 ("type(uint256).max", Uint(256)),
1510 ("type(int128).max", Int(128)),
1511 ("type(int256).max", Int(256)),
1512 ("type(Enum1).min", Uint(256)),
1513 ("type(Enum1).max", Uint(256)),
1514 ("this.run.address", Address),
1516 ("this.run.selector", FixedBytes(4)),
1517 ]
1518 };
1519
1520 generic_type_test(&mut source(), global_variables);
1521 }
1522
1523 #[track_caller]
1524 fn source() -> SessionSource {
1525 static PRE_INSTALL_SOLC_LOCK: Mutex<bool> = Mutex::new(false);
1527
1528 let version = "0.8.20";
1531 for _ in 0..3 {
1532 let mut is_preinstalled = PRE_INSTALL_SOLC_LOCK.lock().unwrap();
1533 if !*is_preinstalled {
1534 let solc = Solc::find_or_install(&version.parse().unwrap())
1535 .map(|solc| (solc.version.clone(), solc));
1536 match solc {
1537 Ok((v, solc)) => {
1538 let _ = sh_println!("found installed Solc v{v} @ {}", solc.solc.display());
1540 break;
1541 }
1542 Err(e) => {
1543 let _ = sh_err!("error while trying to re-install Solc v{version}: {e}");
1545 let solc = Solc::blocking_install(&version.parse().unwrap());
1546 if solc.map_err(SolcError::from).is_ok() {
1547 *is_preinstalled = true;
1548 break;
1549 }
1550 }
1551 }
1552 }
1553 }
1554
1555 SessionSource::new(Default::default()).unwrap()
1556 }
1557
1558 fn array(ty: DynSolType) -> DynSolType {
1559 DynSolType::Array(Box::new(ty))
1560 }
1561
1562 fn fixed_array(ty: DynSolType, len: usize) -> DynSolType {
1563 DynSolType::FixedArray(Box::new(ty), len)
1564 }
1565
1566 fn parse(s: &mut SessionSource, input: &str, clear: bool) -> IntermediateOutput {
1567 if clear {
1568 s.clear();
1569 }
1570
1571 *s = s.clone_with_new_line("enum Enum1 { A }".into()).unwrap().0;
1572
1573 let input = format!("{};", input.trim_end().trim_end_matches(';'));
1574 let (mut _s, _) = s.clone_with_new_line(input).unwrap();
1575 *s = _s.clone();
1576 let s = &mut _s;
1577
1578 if let Err(e) = s.parse() {
1579 let source = s.to_repl_source();
1580 panic!("{e}\n\ncould not parse input:\n{source}")
1581 }
1582 s.generate_intermediate_output().expect("could not generate intermediate output")
1583 }
1584
1585 fn expr(stmts: &[pt::Statement]) -> pt::Expression {
1586 match stmts.last().expect("no statements") {
1587 pt::Statement::Expression(_, e) => e.clone(),
1588 s => panic!("Not an expression: {s:?}"),
1589 }
1590 }
1591
1592 fn get_type(
1593 s: &mut SessionSource,
1594 input: &str,
1595 clear: bool,
1596 ) -> (Option<Type>, IntermediateOutput) {
1597 let intermediate = parse(s, input, clear);
1598 let run_func_body = intermediate.run_func_body().expect("no run func body");
1599 let expr = expr(run_func_body);
1600 (Type::from_expression(&expr).map(Type::map_special), intermediate)
1601 }
1602
1603 fn get_type_ethabi(s: &mut SessionSource, input: &str, clear: bool) -> Option<DynSolType> {
1604 let (ty, intermediate) = get_type(s, input, clear);
1605 ty.and_then(|ty| ty.try_as_ethabi(Some(&intermediate)))
1606 }
1607
1608 fn generic_type_test<'a, T, I>(s: &mut SessionSource, input: I)
1609 where
1610 T: AsRef<str> + std::fmt::Display + 'a,
1611 I: IntoIterator<Item = &'a (T, DynSolType)> + 'a,
1612 {
1613 for (input, expected) in input.into_iter() {
1614 let input = input.as_ref();
1615 let ty = get_type_ethabi(s, input, true);
1616 assert_eq!(ty.as_ref(), Some(expected), "\n{input}");
1617 }
1618 }
1619
1620 fn init_tracing() {
1621 let _ = tracing_subscriber::FmtSubscriber::builder()
1622 .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
1623 .try_init();
1624 }
1625}