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 tracing::debug;
21use yansi::Paint;
22
23impl SessionSource {
25 pub async fn execute(&mut self) -> Result<(Address, ChiselResult)> {
34 let output = self.build()?;
36
37 let (bytecode, final_pc) = output.enter(|output| -> Result<_> {
38 let contract = output
39 .repl_contract()
40 .ok_or_else(|| eyre::eyre!("failed to find REPL contract"))?;
41 let bytecode = contract
42 .get_bytecode_bytes()
43 .ok_or_else(|| eyre::eyre!("No bytecode found for `REPL` contract"))?;
44 Ok((bytecode.into_owned(), output.final_pc(contract)?))
45 })?;
46
47 let Some(final_pc) = final_pc else { return Ok(Default::default()) };
48
49 let mut runner = self.build_runner(final_pc).await?;
50 runner.run(bytecode)
51 }
52
53 pub async fn inspect(&self, input: &str) -> Result<(ControlFlow<()>, Option<String>)> {
65 let line = format!("bytes memory inspectoor = abi.encode({input});");
66 let mut source = match self.clone_with_new_line(line) {
67 Ok((source, _)) => source,
68 Err(err) => {
69 debug!(%err, "failed to build new source");
70 return Ok((ControlFlow::Continue(()), None));
71 }
72 };
73
74 let mut source_without_inspector = self.clone();
75
76 let (mut res, err) = match source.execute().await {
79 Ok((_, res)) => (res, None),
80 Err(err) => {
81 debug!(?err, %input, "execution failed");
82 match source_without_inspector.execute().await {
83 Ok((_, res)) => (res, Some(err)),
84 Err(_) => {
85 if self.config.foundry_config.verbosity >= 3 {
86 sh_err!("Could not inspect: {err}")?;
87 }
88 return Ok((ControlFlow::Continue(()), None));
89 }
90 }
91 }
92 };
93
94 if let Some(err) = err {
96 let output = source_without_inspector.build()?;
97
98 let formatted_event =
99 output.enter(|output| output.get_event(input).map(format_event_definition));
100 if let Some(formatted_event) = formatted_event {
101 return Ok((ControlFlow::Break(()), Some(formatted_event?)));
102 }
103
104 if self.config.foundry_config.verbosity >= 3 {
106 sh_err!("Failed eval: {err}")?;
107 }
108
109 debug!(%err, %input, "failed abi encode input");
110 return Ok((ControlFlow::Break(()), None));
111 }
112 drop(source_without_inspector);
113
114 let Some((stack, memory)) = &res.state else {
115 if let Ok(decoder) = ChiselDispatcher::decode_traces(&source.config, &mut res).await {
117 ChiselDispatcher::show_traces(&decoder, &mut res).await?;
118 }
119 let decoded_logs = decode_console_logs(&res.logs);
120 if !decoded_logs.is_empty() {
121 sh_println!("{}", "Logs:".green())?;
122 for log in decoded_logs {
123 sh_println!(" {log}")?;
124 }
125 }
126
127 return Err(eyre::eyre!("Failed to inspect expression"));
128 };
129
130 let generated_output = source.build()?;
133
134 let contract_expr = generated_output
137 .intermediate
138 .repl_contract_expressions
139 .get(input)
140 .or_else(|| source.infer_inner_expr_type());
141
142 let function_call_return_type =
145 Type::get_function_return_type(contract_expr, &generated_output.intermediate);
146
147 let (contract_expr, ty) = if let Some(function_call_return_type) = function_call_return_type
148 {
149 (function_call_return_type.0, function_call_return_type.1)
150 } else {
151 match contract_expr.and_then(|e| {
152 Type::ethabi(e, Some(&generated_output.intermediate)).map(|ty| (e, ty))
153 }) {
154 Some(res) => res,
155 None => return Ok((ControlFlow::Continue(()), None)),
157 }
158 };
159
160 let mut offset = stack.last().unwrap().to::<usize>();
163 let mem_offset = &memory[offset..offset + 32];
164 let len = U256::try_from_be_slice(mem_offset).unwrap().to::<usize>();
165 offset += 32;
166 let data = &memory[offset..offset + len];
167 let token = ty.abi_decode(data).wrap_err("Could not decode inspected values")?;
168 let c = if should_continue(contract_expr) {
169 ControlFlow::Continue(())
170 } else {
171 ControlFlow::Break(())
172 };
173 Ok((c, Some(format_token(token))))
174 }
175
176 fn infer_inner_expr_type(&self) -> Option<&pt::Expression> {
187 let out = self.build().ok()?;
188 let run = out.run_func_body().ok()?.last();
189 match run {
190 Some(pt::Statement::VariableDefinition(
191 _,
192 _,
193 Some(pt::Expression::FunctionCall(_, _, args)),
194 )) => {
195 Some(args.first().unwrap())
199 }
200 _ => None,
201 }
202 }
203
204 async fn build_runner(&mut self, final_pc: usize) -> Result<ChiselRunner> {
205 let env = self.config.evm_opts.evm_env().await?;
206
207 let backend = match self.config.backend.take() {
208 Some(backend) => backend,
209 None => {
210 let fork = self.config.evm_opts.get_fork(&self.config.foundry_config, env.clone());
211 let backend = Backend::spawn(fork)?;
212 self.config.backend = Some(backend.clone());
213 backend
214 }
215 };
216
217 let executor = ExecutorBuilder::new()
218 .inspectors(|stack| {
219 stack.chisel_state(final_pc).trace_mode(TraceMode::Call).cheatcodes(
220 CheatsConfig::new(
221 &self.config.foundry_config,
222 self.config.evm_opts.clone(),
223 None,
224 None,
225 )
226 .into(),
227 )
228 })
229 .gas_limit(self.config.evm_opts.gas_limit())
230 .spec_id(self.config.foundry_config.evm_spec_id())
231 .legacy_assertions(self.config.foundry_config.legacy_assertions)
232 .build(env, backend);
233
234 Ok(ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone()))
235 }
236}
237
238fn format_token(token: DynSolValue) -> String {
241 match token {
242 DynSolValue::Address(a) => {
243 format!("Type: {}\n└ Data: {}", "address".red(), a.cyan())
244 }
245 DynSolValue::FixedBytes(b, byte_len) => {
246 format!(
247 "Type: {}\n└ Data: {}",
248 format!("bytes{byte_len}").red(),
249 hex::encode_prefixed(b).cyan()
250 )
251 }
252 DynSolValue::Int(i, bit_len) => {
253 format!(
254 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
255 format!("int{bit_len}").red(),
256 format!(
257 "0x{}",
258 format!("{i:x}")
259 .char_indices()
260 .skip(64 - bit_len / 4)
261 .take(bit_len / 4)
262 .map(|(_, c)| c)
263 .collect::<String>()
264 )
265 .cyan(),
266 hex::encode_prefixed(B256::from(i)).cyan(),
267 i.cyan()
268 )
269 }
270 DynSolValue::Uint(i, bit_len) => {
271 format!(
272 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
273 format!("uint{bit_len}").red(),
274 format!(
275 "0x{}",
276 format!("{i:x}")
277 .char_indices()
278 .skip(64 - bit_len / 4)
279 .take(bit_len / 4)
280 .map(|(_, c)| c)
281 .collect::<String>()
282 )
283 .cyan(),
284 hex::encode_prefixed(B256::from(i)).cyan(),
285 i.cyan()
286 )
287 }
288 DynSolValue::Bool(b) => {
289 format!("Type: {}\n└ Value: {}", "bool".red(), b.cyan())
290 }
291 DynSolValue::String(_) | DynSolValue::Bytes(_) => {
292 let hex = hex::encode(token.abi_encode());
293 let s = token.as_str();
294 format!(
295 "Type: {}\n{}├ Hex (Memory):\n├─ Length ({}): {}\n├─ Contents ({}): {}\n├ Hex (Tuple Encoded):\n├─ Pointer ({}): {}\n├─ Length ({}): {}\n└─ Contents ({}): {}",
296 if s.is_some() { "string" } else { "dynamic bytes" }.red(),
297 if let Some(s) = s {
298 format!("├ UTF-8: {}\n", s.cyan())
299 } else {
300 String::default()
301 },
302 "[0x00:0x20]".yellow(),
303 format!("0x{}", &hex[64..128]).cyan(),
304 "[0x20:..]".yellow(),
305 format!("0x{}", &hex[128..]).cyan(),
306 "[0x00:0x20]".yellow(),
307 format!("0x{}", &hex[..64]).cyan(),
308 "[0x20:0x40]".yellow(),
309 format!("0x{}", &hex[64..128]).cyan(),
310 "[0x40:..]".yellow(),
311 format!("0x{}", &hex[128..]).cyan(),
312 )
313 }
314 DynSolValue::FixedArray(tokens) | DynSolValue::Array(tokens) => {
315 let mut out = format!(
316 "{}({}) = {}",
317 "array".red(),
318 format!("{}", tokens.len()).yellow(),
319 '['.red()
320 );
321 for token in tokens {
322 out.push_str("\n ├ ");
323 out.push_str(&format_token(token).replace('\n', "\n "));
324 out.push('\n');
325 }
326 out.push_str(&']'.red().to_string());
327 out
328 }
329 DynSolValue::Tuple(tokens) => {
330 let displayed_types = tokens
331 .iter()
332 .map(|t| t.sol_type_name().unwrap_or_default())
333 .collect::<Vec<_>>()
334 .join(", ");
335 let mut out =
336 format!("{}({}) = {}", "tuple".red(), displayed_types.yellow(), '('.red());
337 for token in tokens {
338 out.push_str("\n ├ ");
339 out.push_str(&format_token(token).replace('\n', "\n "));
340 out.push('\n');
341 }
342 out.push_str(&')'.red().to_string());
343 out
344 }
345 _ => {
346 unimplemented!()
347 }
348 }
349}
350
351fn format_event_definition(event_definition: &pt::EventDefinition) -> Result<String> {
362 let event_name = event_definition.name.as_ref().expect("Event has a name").to_string();
363 let inputs = event_definition
364 .fields
365 .iter()
366 .map(|param| {
367 let name = param
368 .name
369 .as_ref()
370 .map(ToString::to_string)
371 .unwrap_or_else(|| "<anonymous>".to_string());
372 let kind = Type::from_expression(¶m.ty)
373 .and_then(Type::into_builtin)
374 .ok_or_else(|| eyre::eyre!("Invalid type in event {event_name}"))?;
375 Ok(EventParam {
376 name,
377 ty: kind.to_string(),
378 components: vec![],
379 indexed: param.indexed,
380 internal_type: None,
381 })
382 })
383 .collect::<Result<Vec<_>>>()?;
384 let event =
385 alloy_json_abi::Event { name: event_name, inputs, anonymous: event_definition.anonymous };
386
387 Ok(format!(
388 "Type: {}\n├ Name: {}\n├ Signature: {:?}\n└ Selector: {:?}",
389 "event".red(),
390 SolidityHelper::new().highlight(&format!(
391 "{}({})",
392 &event.name,
393 &event
394 .inputs
395 .iter()
396 .map(|param| format!(
397 "{}{}{}",
398 param.ty,
399 if param.indexed { " indexed" } else { "" },
400 if param.name.is_empty() {
401 String::default()
402 } else {
403 format!(" {}", ¶m.name)
404 },
405 ))
406 .collect::<Vec<_>>()
407 .join(", ")
408 )),
409 event.signature().cyan(),
410 event.selector().cyan(),
411 ))
412}
413
414#[derive(Clone, Debug, PartialEq)]
420enum Type {
421 Builtin(DynSolType),
423
424 Array(Box<Type>),
426
427 FixedArray(Box<Type>, usize),
429
430 ArrayIndex(Box<Type>, Option<usize>),
432
433 Tuple(Vec<Option<Type>>),
435
436 Function(Box<Type>, Vec<Option<Type>>, Vec<Option<Type>>),
438
439 Access(Box<Type>, String),
441
442 Custom(Vec<String>),
444}
445
446impl Type {
447 fn from_expression(expr: &pt::Expression) -> Option<Self> {
457 match expr {
458 pt::Expression::Type(_, ty) => Self::from_type(ty),
459
460 pt::Expression::Variable(ident) => Some(Self::Custom(vec![ident.name.clone()])),
461
462 pt::Expression::ArraySubscript(_, expr, num) => {
464 Self::from_expression(expr).and_then(|ty| {
467 let boxed = Box::new(ty);
468 let num = num.as_deref().and_then(parse_number_literal).and_then(|n| {
469 usize::try_from(n).ok()
470 });
471 match expr.as_ref() {
472 pt::Expression::Type(_, _) => {
474 if let Some(num) = num {
475 Some(Self::FixedArray(boxed, num))
476 } else {
477 Some(Self::Array(boxed))
478 }
479 }
480 pt::Expression::Variable(_) => {
482 Some(Self::ArrayIndex(boxed, num))
483 }
484 _ => None
485 }
486 })
487 }
488 pt::Expression::ArrayLiteral(_, values) => {
489 values.first().and_then(Self::from_expression).map(|ty| {
490 Self::FixedArray(Box::new(ty), values.len())
491 })
492 }
493
494 pt::Expression::List(_, params) => Some(Self::Tuple(map_parameters(params))),
496
497 pt::Expression::MemberAccess(_, lhs, rhs) => {
499 Self::from_expression(lhs).map(|lhs| {
500 Self::Access(Box::new(lhs), rhs.name.clone())
501 })
502 }
503
504 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),
528
529 pt::Expression::ConditionalOperator(_, _, if_true, if_false) => {
531 Self::from_expression(if_true).or_else(|| Self::from_expression(if_false))
532 }
533
534 pt::Expression::AddressLiteral(_, _) => Some(Self::Builtin(DynSolType::Address)),
536 pt::Expression::HexNumberLiteral(_, s, _) => {
537 match s.parse::<Address>() {
538 Ok(addr) => {
539 if *s == addr.to_checksum(None) {
540 Some(Self::Builtin(DynSolType::Address))
541 } else {
542 Some(Self::Builtin(DynSolType::Uint(256)))
543 }
544 },
545 _ => {
546 Some(Self::Builtin(DynSolType::Uint(256)))
547 }
548 }
549 }
550
551 pt::Expression::Negate(_, inner) => Self::from_expression(inner).map(Self::invert_int),
554
555 pt::Expression::Add(_, lhs, rhs) |
559 pt::Expression::Subtract(_, lhs, rhs) |
560 pt::Expression::Multiply(_, lhs, rhs) |
561 pt::Expression::Divide(_, lhs, rhs) => {
562 match (Self::ethabi(lhs, None), Self::ethabi(rhs, None)) {
563 (Some(DynSolType::Int(_)), Some(DynSolType::Int(_))) |
564 (Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) |
565 (Some(DynSolType::Uint(_)), Some(DynSolType::Int(_))) => {
566 Some(Self::Builtin(DynSolType::Int(256)))
567 }
568 _ => {
569 Some(Self::Builtin(DynSolType::Uint(256)))
570 }
571 }
572 }
573
574 pt::Expression::Modulo(_, _, _) |
576 pt::Expression::Power(_, _, _) |
577 pt::Expression::BitwiseOr(_, _, _) |
578 pt::Expression::BitwiseAnd(_, _, _) |
579 pt::Expression::BitwiseXor(_, _, _) |
580 pt::Expression::ShiftRight(_, _, _) |
581 pt::Expression::ShiftLeft(_, _, _) |
582 pt::Expression::NumberLiteral(_, _, _, _) => Some(Self::Builtin(DynSolType::Uint(256))),
583
584 pt::Expression::RationalNumberLiteral(_, _, _, _, _) => {
586 Some(Self::Builtin(DynSolType::Uint(256)))
587 }
588
589 pt::Expression::BoolLiteral(_, _) |
591 pt::Expression::And(_, _, _) |
592 pt::Expression::Or(_, _, _) |
593 pt::Expression::Equal(_, _, _) |
594 pt::Expression::NotEqual(_, _, _) |
595 pt::Expression::Less(_, _, _) |
596 pt::Expression::LessEqual(_, _, _) |
597 pt::Expression::More(_, _, _) |
598 pt::Expression::MoreEqual(_, _, _) |
599 pt::Expression::Not(_, _) => Some(Self::Builtin(DynSolType::Bool)),
600
601 pt::Expression::StringLiteral(_) => Some(Self::Builtin(DynSolType::String)),
603
604 pt::Expression::HexLiteral(_) => Some(Self::Builtin(DynSolType::Bytes)),
606
607 pt::Expression::FunctionCall(_, name, args) => {
609 Self::from_expression(name).map(|name| {
610 let args = args.iter().map(Self::from_expression).collect();
611 Self::Function(Box::new(name), args, vec![])
612 })
613 }
614 pt::Expression::NamedFunctionCall(_, name, args) => {
615 Self::from_expression(name).map(|name| {
616 let args = args.iter().map(|arg| Self::from_expression(&arg.expr)).collect();
617 Self::Function(Box::new(name), args, vec![])
618 })
619 }
620
621 pt::Expression::Delete(_, _) | pt::Expression::FunctionCallBlock(_, _, _) => None,
623 }
624 }
625
626 fn from_type(ty: &pt::Type) -> Option<Self> {
636 let ty = match ty {
637 pt::Type::Address | pt::Type::AddressPayable | pt::Type::Payable => {
638 Self::Builtin(DynSolType::Address)
639 }
640 pt::Type::Bool => Self::Builtin(DynSolType::Bool),
641 pt::Type::String => Self::Builtin(DynSolType::String),
642 pt::Type::Int(size) => Self::Builtin(DynSolType::Int(*size as usize)),
643 pt::Type::Uint(size) => Self::Builtin(DynSolType::Uint(*size as usize)),
644 pt::Type::Bytes(size) => Self::Builtin(DynSolType::FixedBytes(*size as usize)),
645 pt::Type::DynamicBytes => Self::Builtin(DynSolType::Bytes),
646 pt::Type::Mapping { value, .. } => Self::from_expression(value)?,
647 pt::Type::Function { params, returns, .. } => {
648 let params = map_parameters(params);
649 let returns = returns
650 .as_ref()
651 .map(|(returns, _)| map_parameters(returns))
652 .unwrap_or_default();
653 Self::Function(
654 Box::new(Self::Custom(vec!["__fn_type__".to_string()])),
655 params,
656 returns,
657 )
658 }
659 pt::Type::Rational => return None,
661 };
662 Some(ty)
663 }
664
665 fn map_special(self) -> Self {
669 if !matches!(self, Self::Function(_, _, _) | Self::Access(_, _) | Self::Custom(_)) {
670 return self;
671 }
672
673 let mut types = Vec::with_capacity(5);
674 let mut args = None;
675 self.recurse(&mut types, &mut args);
676
677 let len = types.len();
678 if len == 0 {
679 return self;
680 }
681
682 #[expect(clippy::single_match)]
684 match &self {
685 Self::Access(inner, access) => {
686 if let Some(ty) = inner.as_ref().clone().try_as_ethabi(None) {
687 let ty = Self::Builtin(ty);
689 match access.as_str() {
690 "length" if ty.is_dynamic() || ty.is_array() || ty.is_fixed_bytes() => {
691 return Self::Builtin(DynSolType::Uint(256));
692 }
693 "pop" if ty.is_dynamic_array() => return ty,
694 _ => {}
695 }
696 }
697 }
698 _ => {}
699 }
700
701 let this = {
702 let name = types.last().unwrap().as_str();
703 match len {
704 0 => unreachable!(),
705 1 => match name {
706 "gasleft" | "addmod" | "mulmod" => Some(DynSolType::Uint(256)),
707 "keccak256" | "sha256" | "blockhash" => Some(DynSolType::FixedBytes(32)),
708 "ripemd160" => Some(DynSolType::FixedBytes(20)),
709 "ecrecover" => Some(DynSolType::Address),
710 _ => None,
711 },
712 2 => {
713 let access = types.first().unwrap().as_str();
714 match name {
715 "block" => match access {
716 "coinbase" => Some(DynSolType::Address),
717 "timestamp" | "difficulty" | "prevrandao" | "number" | "gaslimit"
718 | "chainid" | "basefee" | "blobbasefee" => Some(DynSolType::Uint(256)),
719 _ => None,
720 },
721 "msg" => match access {
722 "sender" => Some(DynSolType::Address),
723 "gas" => Some(DynSolType::Uint(256)),
724 "value" => Some(DynSolType::Uint(256)),
725 "data" => Some(DynSolType::Bytes),
726 "sig" => Some(DynSolType::FixedBytes(4)),
727 _ => None,
728 },
729 "tx" => match access {
730 "origin" => Some(DynSolType::Address),
731 "gasprice" => Some(DynSolType::Uint(256)),
732 _ => None,
733 },
734 "abi" => match access {
735 "decode" => {
736 let mut args = args.unwrap();
740 let last = args.pop().unwrap();
741 match last {
742 Some(ty) => {
743 return match ty {
744 Self::Tuple(_) => ty,
745 ty => Self::Tuple(vec![Some(ty)]),
746 };
747 }
748 None => None,
749 }
750 }
751 s if s.starts_with("encode") => Some(DynSolType::Bytes),
752 _ => None,
753 },
754 "address" => match access {
755 "balance" => Some(DynSolType::Uint(256)),
756 "code" => Some(DynSolType::Bytes),
757 "codehash" => Some(DynSolType::FixedBytes(32)),
758 "send" => Some(DynSolType::Bool),
759 _ => None,
760 },
761 "type" => match access {
762 "name" => Some(DynSolType::String),
763 "creationCode" | "runtimeCode" => Some(DynSolType::Bytes),
764 "interfaceId" => Some(DynSolType::FixedBytes(4)),
765 "min" | "max" => Some(
766 (|| args?.pop()??.into_builtin())()
768 .unwrap_or(DynSolType::Uint(256)),
769 ),
770 _ => None,
771 },
772 "string" => match access {
773 "concat" => Some(DynSolType::String),
774 _ => None,
775 },
776 "bytes" => match access {
777 "concat" => Some(DynSolType::Bytes),
778 _ => None,
779 },
780 _ => None,
781 }
782 }
783 _ => None,
784 }
785 };
786
787 this.map(Self::Builtin).unwrap_or_else(|| match types.last().unwrap().as_str() {
788 "this" | "super" => Self::Custom(types),
789 _ => match self {
790 Self::Custom(_) | Self::Access(_, _) => Self::Custom(types),
791 Self::Function(_, _, _) => self,
792 _ => unreachable!(),
793 },
794 })
795 }
796
797 fn recurse(&self, types: &mut Vec<String>, args: &mut Option<Vec<Option<Self>>>) {
800 match self {
801 Self::Builtin(ty) => types.push(ty.to_string()),
802 Self::Custom(tys) => types.extend(tys.clone()),
803 Self::Access(expr, name) => {
804 types.push(name.clone());
805 expr.recurse(types, args);
806 }
807 Self::Function(fn_name, fn_args, _fn_ret) => {
808 if args.is_none() && !fn_args.is_empty() {
809 *args = Some(fn_args.clone());
810 }
811 fn_name.recurse(types, args);
812 }
813 _ => {}
814 }
815 }
816
817 fn infer_custom_type(
831 intermediate: &IntermediateOutput,
832 custom_type: &mut Vec<String>,
833 contract_name: Option<String>,
834 ) -> Result<Option<DynSolType>> {
835 if let Some("this") | Some("super") = custom_type.last().map(String::as_str) {
836 custom_type.pop();
837 }
838 if custom_type.is_empty() {
839 return Ok(None);
840 }
841
842 if let Some(contract_name) = contract_name {
845 let intermediate_contract = intermediate
846 .intermediate_contracts
847 .get(&contract_name)
848 .ok_or_else(|| eyre::eyre!("Could not find intermediate contract!"))?;
849
850 let cur_type = custom_type.last().unwrap();
851 if let Some(func) = intermediate_contract.function_definitions.get(cur_type) {
852 if let res @ Some(_) = func_members(func, custom_type) {
854 return Ok(res);
855 }
856
857 if func.returns.is_empty() {
860 eyre::bail!(
861 "This call expression does not return any values to inspect. Insert as statement."
862 )
863 }
864
865 let (_, param) = func.returns.first().unwrap();
867 let return_ty = ¶m.as_ref().unwrap().ty;
869
870 if let pt::Expression::Variable(ident) = return_ty {
874 custom_type.push(ident.name.clone());
875 return Self::infer_custom_type(intermediate, custom_type, Some(contract_name));
876 }
877
878 if let Some(pt::FunctionAttribute::Mutability(_mut)) = func
882 .attributes
883 .iter()
884 .find(|attr| matches!(attr, pt::FunctionAttribute::Mutability(_)))
885 {
886 if let pt::Mutability::Payable(_) = _mut {
887 eyre::bail!("This function mutates state. Insert as a statement.")
888 }
889 } else {
890 eyre::bail!("This function mutates state. Insert as a statement.")
891 }
892
893 Ok(Self::ethabi(return_ty, Some(intermediate)))
894 } else if let Some(var) = intermediate_contract.variable_definitions.get(cur_type) {
895 Self::infer_var_expr(&var.ty, Some(intermediate), custom_type)
896 } else if let Some(strukt) = intermediate_contract.struct_definitions.get(cur_type) {
897 let inner_types = strukt
898 .fields
899 .iter()
900 .map(|var| {
901 Self::ethabi(&var.ty, Some(intermediate))
902 .ok_or_else(|| eyre::eyre!("Struct `{cur_type}` has invalid fields"))
903 })
904 .collect::<Result<Vec<_>>>()?;
905 Ok(Some(DynSolType::Tuple(inner_types)))
906 } else {
907 eyre::bail!(
908 "Could not find any definition in contract \"{contract_name}\" for type: {custom_type:?}"
909 )
910 }
911 } else {
912 if let Ok(res) = Self::infer_custom_type(intermediate, custom_type, Some("REPL".into()))
915 {
916 return Ok(res);
917 }
918
919 let name = custom_type.last().unwrap();
922 let contract = intermediate.intermediate_contracts.get(name);
923 if contract.is_some() {
924 let contract_name = custom_type.pop();
925 return Self::infer_custom_type(intermediate, custom_type, contract_name);
926 }
927
928 let name = custom_type.last().unwrap();
930 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
931 return Self::infer_var_expr(expr, Some(intermediate), custom_type);
932 }
933
934 Ok(None)
937 }
938 }
939
940 fn infer_var_expr(
942 expr: &pt::Expression,
943 intermediate: Option<&IntermediateOutput>,
944 custom_type: &mut Vec<String>,
945 ) -> Result<Option<DynSolType>> {
946 let res = match &expr {
948 pt::Expression::Variable(ident) => {
950 let name = &ident.name;
951
952 if let Some(intermediate) = intermediate {
953 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
955 Self::infer_var_expr(expr, Some(intermediate), custom_type)
956 } else if intermediate.intermediate_contracts.contains_key(name) {
957 if custom_type.len() > 1 {
958 custom_type.pop();
960 Self::infer_custom_type(intermediate, custom_type, Some(name.clone()))
961 } else {
962 Ok(Some(DynSolType::Address))
964 }
965 } else {
966 Err(eyre::eyre!("Could not infer variable type"))
967 }
968 } else {
969 Ok(None)
970 }
971 }
972 ty => Ok(Self::ethabi(ty, intermediate)),
973 };
974 match res {
977 Ok(Some(ty)) => {
978 let box_ty = Box::new(Self::Builtin(ty.clone()));
979 let access = Self::Access(box_ty, custom_type.drain(..).next().unwrap_or_default());
980 if let Some(mapped) = access.map_special().try_as_ethabi(intermediate) {
981 Ok(Some(mapped))
982 } else {
983 Ok(Some(ty))
984 }
985 }
986 res => res,
987 }
988 }
989
990 fn try_as_ethabi(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
998 match self {
999 Self::Builtin(ty) => Some(ty),
1000 Self::Tuple(types) => Some(DynSolType::Tuple(types_to_parameters(types, intermediate))),
1001 Self::Array(inner) => match *inner {
1002 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
1003 _ => inner
1004 .try_as_ethabi(intermediate)
1005 .map(|inner| DynSolType::Array(Box::new(inner))),
1006 },
1007 Self::FixedArray(inner, size) => match *inner {
1008 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
1009 _ => inner
1010 .try_as_ethabi(intermediate)
1011 .map(|inner| DynSolType::FixedArray(Box::new(inner), size)),
1012 },
1013 ty @ Self::ArrayIndex(_, _) => ty.into_array_index(intermediate),
1014 Self::Function(ty, _, _) => ty.try_as_ethabi(intermediate),
1015 Self::Access(_, _) => None,
1017 Self::Custom(mut types) => {
1018 intermediate.and_then(|intermediate| {
1020 Self::infer_custom_type(intermediate, &mut types, None).ok().flatten()
1021 })
1022 }
1023 }
1024 }
1025
1026 fn ethabi(
1028 expr: &pt::Expression,
1029 intermediate: Option<&IntermediateOutput>,
1030 ) -> Option<DynSolType> {
1031 Self::from_expression(expr)
1032 .map(Self::map_special)
1033 .and_then(|ty| ty.try_as_ethabi(intermediate))
1034 }
1035
1036 fn get_function_return_type<'a>(
1038 contract_expr: Option<&'a pt::Expression>,
1039 intermediate: &IntermediateOutput,
1040 ) -> Option<(&'a pt::Expression, DynSolType)> {
1041 let function_call = match contract_expr? {
1042 pt::Expression::FunctionCall(_, function_call, _) => function_call,
1043 _ => return None,
1044 };
1045 let (contract_name, function_name) = match function_call.as_ref() {
1046 pt::Expression::MemberAccess(_, contract_name, function_name) => {
1047 (contract_name, function_name)
1048 }
1049 _ => return None,
1050 };
1051 let contract_name = match contract_name.as_ref() {
1052 pt::Expression::Variable(contract_name) => contract_name.to_owned(),
1053 _ => return None,
1054 };
1055
1056 let pt::Expression::Variable(contract_name) =
1057 intermediate.repl_contract_expressions.get(&contract_name.name)?
1058 else {
1059 return None;
1060 };
1061
1062 let contract = intermediate
1063 .intermediate_contracts
1064 .get(&contract_name.name)?
1065 .function_definitions
1066 .get(&function_name.name)?;
1067 let return_parameter = contract.as_ref().returns.first()?.to_owned().1?;
1068 Self::ethabi(&return_parameter.ty, Some(intermediate)).map(|p| (contract_expr.unwrap(), p))
1069 }
1070
1071 fn invert_int(self) -> Self {
1073 match self {
1074 Self::Builtin(DynSolType::Uint(n)) => Self::Builtin(DynSolType::Int(n)),
1075 Self::Builtin(DynSolType::Int(n)) => Self::Builtin(DynSolType::Uint(n)),
1076 x => x,
1077 }
1078 }
1079
1080 #[inline]
1082 fn into_builtin(self) -> Option<DynSolType> {
1083 match self {
1084 Self::Builtin(ty) => Some(ty),
1085 _ => None,
1086 }
1087 }
1088
1089 fn into_array_index(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
1091 match self {
1092 Self::Array(inner) | Self::FixedArray(inner, _) | Self::ArrayIndex(inner, _) => {
1093 match inner.try_as_ethabi(intermediate) {
1094 Some(DynSolType::Array(inner)) | Some(DynSolType::FixedArray(inner, _)) => {
1095 Some(*inner)
1096 }
1097 Some(DynSolType::Bytes)
1098 | Some(DynSolType::String)
1099 | Some(DynSolType::FixedBytes(_)) => Some(DynSolType::FixedBytes(1)),
1100 ty => ty,
1101 }
1102 }
1103 _ => None,
1104 }
1105 }
1106
1107 #[inline]
1109 fn is_dynamic(&self) -> bool {
1110 match self {
1111 Self::Builtin(DynSolType::Bytes | DynSolType::String | DynSolType::Array(_)) => true,
1114 Self::Array(_) => true,
1115 _ => false,
1116 }
1117 }
1118
1119 #[inline]
1121 fn is_array(&self) -> bool {
1122 matches!(
1123 self,
1124 Self::Array(_)
1125 | Self::FixedArray(_, _)
1126 | Self::Builtin(DynSolType::Array(_))
1127 | Self::Builtin(DynSolType::FixedArray(_, _))
1128 )
1129 }
1130
1131 #[inline]
1133 fn is_dynamic_array(&self) -> bool {
1134 matches!(self, Self::Array(_) | Self::Builtin(DynSolType::Array(_)))
1135 }
1136
1137 fn is_fixed_bytes(&self) -> bool {
1138 matches!(self, Self::Builtin(DynSolType::FixedBytes(_)))
1139 }
1140}
1141
1142#[inline]
1146fn func_members(func: &pt::FunctionDefinition, custom_type: &[String]) -> Option<DynSolType> {
1147 if !matches!(func.ty, pt::FunctionTy::Function) {
1148 return None;
1149 }
1150
1151 let vis = func.attributes.iter().find_map(|attr| match attr {
1152 pt::FunctionAttribute::Visibility(vis) => Some(vis),
1153 _ => None,
1154 });
1155 match vis {
1156 Some(pt::Visibility::External(_)) | Some(pt::Visibility::Public(_)) => {
1157 match custom_type.first().unwrap().as_str() {
1158 "address" => Some(DynSolType::Address),
1159 "selector" => Some(DynSolType::FixedBytes(4)),
1160 _ => None,
1161 }
1162 }
1163 _ => None,
1164 }
1165}
1166
1167#[inline]
1169fn should_continue(expr: &pt::Expression) -> bool {
1170 match expr {
1171 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(_, _, _) => {
1188 true
1189 }
1190
1191 pt::Expression::FunctionCall(_, lhs, _) => {
1193 match lhs.as_ref() {
1194 pt::Expression::MemberAccess(_, _inner, access) => access.name == "pop",
1195 _ => false
1196 }
1197 }
1198
1199 _ => false
1200 }
1201}
1202
1203fn map_parameters(params: &[(pt::Loc, Option<pt::Parameter>)]) -> Vec<Option<Type>> {
1204 params
1205 .iter()
1206 .map(|(_, param)| param.as_ref().and_then(|param| Type::from_expression(¶m.ty)))
1207 .collect()
1208}
1209
1210fn types_to_parameters(
1211 types: Vec<Option<Type>>,
1212 intermediate: Option<&IntermediateOutput>,
1213) -> Vec<DynSolType> {
1214 types.into_iter().filter_map(|ty| ty.and_then(|ty| ty.try_as_ethabi(intermediate))).collect()
1215}
1216
1217fn parse_number_literal(expr: &pt::Expression) -> Option<U256> {
1218 match expr {
1219 pt::Expression::NumberLiteral(_, num, exp, unit) => {
1220 let num = num.parse::<U256>().unwrap_or(U256::ZERO);
1221 let exp = exp.parse().unwrap_or(0u32);
1222 if exp > 77 {
1223 None
1224 } else {
1225 let exp = U256::from(10usize.pow(exp));
1226 let unit_mul = unit_multiplier(unit).ok()?;
1227 Some(num * exp * unit_mul)
1228 }
1229 }
1230 pt::Expression::HexNumberLiteral(_, num, unit) => {
1231 let unit_mul = unit_multiplier(unit).ok()?;
1232 num.parse::<U256>().map(|num| num * unit_mul).ok()
1233 }
1234 pt::Expression::RationalNumberLiteral(..) => None,
1236 _ => None,
1237 }
1238}
1239
1240#[inline]
1241fn unit_multiplier(unit: &Option<pt::Identifier>) -> Result<U256> {
1242 if let Some(unit) = unit {
1243 let mul = match unit.name.as_str() {
1244 "seconds" => 1,
1245 "minutes" => 60,
1246 "hours" => 60 * 60,
1247 "days" => 60 * 60 * 24,
1248 "weeks" => 60 * 60 * 24 * 7,
1249 "wei" => 1,
1250 "gwei" => 10_usize.pow(9),
1251 "ether" => 10_usize.pow(18),
1252 other => eyre::bail!("unknown unit: {other}"),
1253 };
1254 Ok(U256::from(mul))
1255 } else {
1256 Ok(U256::from(1))
1257 }
1258}
1259
1260#[cfg(test)]
1261mod tests {
1262 use super::*;
1263 use foundry_compilers::{error::SolcError, solc::Solc};
1264 use std::sync::Mutex;
1265
1266 #[test]
1267 fn test_expressions() {
1268 static EXPRESSIONS: &[(&str, DynSolType)] = {
1269 use DynSolType::*;
1270 &[
1271 ("1 seconds", Uint(256)),
1274 ("1 minutes", Uint(256)),
1275 ("1 hours", Uint(256)),
1276 ("1 days", Uint(256)),
1277 ("1 weeks", Uint(256)),
1278 ("1 wei", Uint(256)),
1279 ("1 gwei", Uint(256)),
1280 ("1 ether", Uint(256)),
1281 ("-1 seconds", Int(256)),
1283 ("-1 minutes", Int(256)),
1284 ("-1 hours", Int(256)),
1285 ("-1 days", Int(256)),
1286 ("-1 weeks", Int(256)),
1287 ("-1 wei", Int(256)),
1288 ("-1 gwei", Int(256)),
1289 ("-1 ether", Int(256)),
1290 ("true ? 1 : 0", Uint(256)),
1292 ("true ? -1 : 0", Int(256)),
1293 ("1 + 1", Uint(256)),
1299 ("1 - 1", Uint(256)),
1300 ("1 * 1", Uint(256)),
1301 ("1 / 1", Uint(256)),
1302 ("1 % 1", Uint(256)),
1303 ("1 ** 1", Uint(256)),
1304 ("1 | 1", Uint(256)),
1305 ("1 & 1", Uint(256)),
1306 ("1 ^ 1", Uint(256)),
1307 ("1 >> 1", Uint(256)),
1308 ("1 << 1", Uint(256)),
1309 ("int(1) + 1", Int(256)),
1311 ("int(1) - 1", Int(256)),
1312 ("int(1) * 1", Int(256)),
1313 ("int(1) / 1", Int(256)),
1314 ("1 + int(1)", Int(256)),
1315 ("1 - int(1)", Int(256)),
1316 ("1 * int(1)", Int(256)),
1317 ("1 / int(1)", Int(256)),
1318 ("uint256 a; a--", Uint(256)),
1322 ("uint256 a; --a", Uint(256)),
1323 ("uint256 a; a++", Uint(256)),
1324 ("uint256 a; ++a", 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 ("uint256 a; a /= 1", Uint(256)),
1330 ("uint256 a; a %= 1", Uint(256)),
1331 ("uint256 a; a &= 1", Uint(256)),
1332 ("uint256 a; a |= 1", Uint(256)),
1333 ("uint256 a; a ^= 1", Uint(256)),
1334 ("uint256 a; a <<= 1", Uint(256)),
1335 ("uint256 a; a >>= 1", Uint(256)),
1336 ("true && true", Bool),
1340 ("true || true", Bool),
1341 ("true == true", Bool),
1342 ("true != true", Bool),
1343 ("true < true", Bool),
1344 ("true <= true", Bool),
1345 ("true > true", Bool),
1346 ("true >= true", Bool),
1347 ("!true", Bool),
1348 ]
1350 };
1351
1352 let source = &mut source();
1353
1354 let array_expressions: &[(&str, DynSolType)] = &[
1355 ("[1, 2, 3]", fixed_array(DynSolType::Uint(256), 3)),
1356 ("[uint8(1), 2, 3]", fixed_array(DynSolType::Uint(8), 3)),
1357 ("[int8(1), 2, 3]", fixed_array(DynSolType::Int(8), 3)),
1358 ("new uint256[](3)", array(DynSolType::Uint(256))),
1359 ("uint256[] memory a = new uint256[](3);\na[0]", DynSolType::Uint(256)),
1360 ("uint256[] memory a = new uint256[](3);\na[0:3]", array(DynSolType::Uint(256))),
1361 ];
1362 generic_type_test(source, array_expressions);
1363 generic_type_test(source, EXPRESSIONS);
1364 }
1365
1366 #[test]
1367 fn test_types() {
1368 static TYPES: &[(&str, DynSolType)] = {
1369 use DynSolType::*;
1370 &[
1371 ("bool", Bool),
1373 ("true", Bool),
1374 ("false", Bool),
1375 ("uint", Uint(256)),
1379 ("uint(1)", Uint(256)),
1380 ("1", Uint(256)),
1381 ("0x01", Uint(256)),
1382 ("int", Int(256)),
1383 ("int(1)", Int(256)),
1384 ("int(-1)", Int(256)),
1385 ("-1", Int(256)),
1386 ("-0x01", Int(256)),
1387 ("address", Address),
1391 ("address(0)", Address),
1392 ("0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990", Address),
1393 ("payable(0)", Address),
1394 ("payable(address(0))", Address),
1395 ("string", String),
1399 ("string(\"hello world\")", String),
1400 ("\"hello world\"", String),
1401 ("unicode\"hello world 😀\"", String),
1402 ("bytes", Bytes),
1406 ("bytes(\"hello world\")", Bytes),
1407 ("bytes(unicode\"hello world 😀\")", Bytes),
1408 ("hex\"68656c6c6f20776f726c64\"", Bytes),
1409 ]
1411 };
1412
1413 let mut types: Vec<(String, DynSolType)> = Vec::with_capacity(96 + 32 + 100);
1414 for (n, b) in (8..=256).step_by(8).zip(1..=32) {
1415 types.push((format!("uint{n}(0)"), DynSolType::Uint(n)));
1416 types.push((format!("int{n}(0)"), DynSolType::Int(n)));
1417 types.push((format!("bytes{b}(0x00)"), DynSolType::FixedBytes(b)));
1418 }
1419
1420 for n in 0..=32 {
1421 types.push((
1422 format!("uint256[{n}]"),
1423 DynSolType::FixedArray(Box::new(DynSolType::Uint(256)), n),
1424 ));
1425 }
1426
1427 generic_type_test(&mut source(), TYPES);
1428 generic_type_test(&mut source(), &types);
1429 }
1430
1431 #[test]
1432 fn test_global_vars() {
1433 init_tracing();
1434
1435 let global_variables = {
1437 use DynSolType::*;
1438 &[
1439 ("abi.decode(bytes, (uint8[13]))", Tuple(vec![FixedArray(Box::new(Uint(8)), 13)])),
1441 ("abi.decode(bytes, (address, bytes))", Tuple(vec![Address, Bytes])),
1442 ("abi.decode(bytes, (uint112, uint48))", Tuple(vec![Uint(112), Uint(48)])),
1443 ("abi.encode(_, _)", Bytes),
1444 ("abi.encodePacked(_, _)", Bytes),
1445 ("abi.encodeWithSelector(bytes4, _, _)", Bytes),
1446 ("abi.encodeCall(func(), (_, _))", Bytes),
1447 ("abi.encodeWithSignature(string, _, _)", Bytes),
1448 ("bytes.concat()", Bytes),
1452 ("bytes.concat(_)", Bytes),
1453 ("bytes.concat(_, _)", Bytes),
1454 ("string.concat()", String),
1455 ("string.concat(_)", String),
1456 ("string.concat(_, _)", String),
1457 ("block.basefee", Uint(256)),
1461 ("block.chainid", Uint(256)),
1462 ("block.coinbase", Address),
1463 ("block.difficulty", Uint(256)),
1464 ("block.gaslimit", Uint(256)),
1465 ("block.number", Uint(256)),
1466 ("block.timestamp", Uint(256)),
1467 ("gasleft()", Uint(256)),
1471 ("msg.data", Bytes),
1472 ("msg.sender", Address),
1473 ("msg.sig", FixedBytes(4)),
1474 ("msg.value", Uint(256)),
1475 ("tx.gasprice", Uint(256)),
1476 ("tx.origin", Address),
1477 ("blockhash(uint)", FixedBytes(32)),
1488 ("keccak256(bytes)", FixedBytes(32)),
1489 ("sha256(bytes)", FixedBytes(32)),
1490 ("ripemd160(bytes)", FixedBytes(20)),
1491 ("ecrecover(bytes32, uint8, bytes32, bytes32)", Address),
1492 ("addmod(uint, uint, uint)", Uint(256)),
1493 ("mulmod(uint, uint, uint)", Uint(256)),
1494 ("address(_)", Address),
1498 ("address(this)", Address),
1499 ("address.balance", Uint(256)),
1502 ("address.code", Bytes),
1503 ("address.codehash", FixedBytes(32)),
1504 ("address.send(uint256)", Bool),
1505 ("type(C).name", String),
1510 ("type(C).creationCode", Bytes),
1511 ("type(C).runtimeCode", Bytes),
1512 ("type(I).interfaceId", FixedBytes(4)),
1513 ("type(uint256).min", Uint(256)),
1514 ("type(int128).min", Int(128)),
1515 ("type(int256).min", Int(256)),
1516 ("type(uint256).max", Uint(256)),
1517 ("type(int128).max", Int(128)),
1518 ("type(int256).max", Int(256)),
1519 ("type(Enum1).min", Uint(256)),
1520 ("type(Enum1).max", Uint(256)),
1521 ("this.run.address", Address),
1523 ("this.run.selector", FixedBytes(4)),
1524 ]
1525 };
1526
1527 generic_type_test(&mut source(), global_variables);
1528 }
1529
1530 #[track_caller]
1531 fn source() -> SessionSource {
1532 static PRE_INSTALL_SOLC_LOCK: Mutex<bool> = Mutex::new(false);
1534
1535 let version = "0.8.20";
1538 for _ in 0..3 {
1539 let mut is_preinstalled = PRE_INSTALL_SOLC_LOCK.lock().unwrap();
1540 if !*is_preinstalled {
1541 let solc = Solc::find_or_install(&version.parse().unwrap())
1542 .map(|solc| (solc.version.clone(), solc));
1543 match solc {
1544 Ok((v, solc)) => {
1545 let _ = sh_println!("found installed Solc v{v} @ {}", solc.solc.display());
1547 break;
1548 }
1549 Err(e) => {
1550 let _ = sh_err!("error while trying to re-install Solc v{version}: {e}");
1552 let solc = Solc::blocking_install(&version.parse().unwrap());
1553 if solc.map_err(SolcError::from).is_ok() {
1554 *is_preinstalled = true;
1555 break;
1556 }
1557 }
1558 }
1559 }
1560 }
1561
1562 SessionSource::new(Default::default()).unwrap()
1563 }
1564
1565 fn array(ty: DynSolType) -> DynSolType {
1566 DynSolType::Array(Box::new(ty))
1567 }
1568
1569 fn fixed_array(ty: DynSolType, len: usize) -> DynSolType {
1570 DynSolType::FixedArray(Box::new(ty), len)
1571 }
1572
1573 fn parse(s: &mut SessionSource, input: &str, clear: bool) -> IntermediateOutput {
1574 if clear {
1575 s.clear();
1576 }
1577
1578 *s = s.clone_with_new_line("enum Enum1 { A }".into()).unwrap().0;
1579
1580 let input = format!("{};", input.trim_end().trim_end_matches(';'));
1581 let (mut _s, _) = s.clone_with_new_line(input).unwrap();
1582 *s = _s.clone();
1583 let s = &mut _s;
1584
1585 if let Err(e) = s.parse() {
1586 let source = s.to_repl_source();
1587 panic!("{e}\n\ncould not parse input:\n{source}")
1588 }
1589 s.generate_intermediate_output().expect("could not generate intermediate output")
1590 }
1591
1592 fn expr(stmts: &[pt::Statement]) -> pt::Expression {
1593 match stmts.last().expect("no statements") {
1594 pt::Statement::Expression(_, e) => e.clone(),
1595 s => panic!("Not an expression: {s:?}"),
1596 }
1597 }
1598
1599 fn get_type(
1600 s: &mut SessionSource,
1601 input: &str,
1602 clear: bool,
1603 ) -> (Option<Type>, IntermediateOutput) {
1604 let intermediate = parse(s, input, clear);
1605 let run_func_body = intermediate.run_func_body().expect("no run func body");
1606 let expr = expr(run_func_body);
1607 (Type::from_expression(&expr).map(Type::map_special), intermediate)
1608 }
1609
1610 fn get_type_ethabi(s: &mut SessionSource, input: &str, clear: bool) -> Option<DynSolType> {
1611 let (ty, intermediate) = get_type(s, input, clear);
1612 ty.and_then(|ty| ty.try_as_ethabi(Some(&intermediate)))
1613 }
1614
1615 fn generic_type_test<'a, T, I>(s: &mut SessionSource, input: I)
1616 where
1617 T: AsRef<str> + std::fmt::Display + 'a,
1618 I: IntoIterator<Item = &'a (T, DynSolType)> + 'a,
1619 {
1620 for (input, expected) in input.into_iter() {
1621 let input = input.as_ref();
1622 let ty = get_type_ethabi(s, input, true);
1623 assert_eq!(ty.as_ref(), Some(expected), "\n{input}");
1624 }
1625 }
1626
1627 fn init_tracing() {
1628 let _ = tracing_subscriber::FmtSubscriber::builder()
1629 .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
1630 .try_init();
1631 }
1632}