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 data = (|| -> Option<_> {
156 let mut offset: usize = stack.last()?.try_into().ok()?;
157 debug!("inspect memory @ {offset}: {}", hex::encode(memory));
158 let mem_offset = memory.get(offset..offset + 32)?;
159 let len: usize = U256::try_from_be_slice(mem_offset)?.try_into().ok()?;
160 offset += 32;
161 memory.get(offset..offset + len)
162 })();
163 let Some(data) = data else {
164 eyre::bail!("Failed to inspect last expression: could not retrieve data from memory")
165 };
166 let token = ty.abi_decode(data).wrap_err("Could not decode inspected values")?;
167 let c = if should_continue(contract_expr) {
168 ControlFlow::Continue(())
169 } else {
170 ControlFlow::Break(())
171 };
172 Ok((c, Some(format_token(token))))
173 }
174
175 fn infer_inner_expr_type(&self) -> Option<&pt::Expression> {
186 let out = self.build().ok()?;
187 let run = out.run_func_body().ok()?.last();
188 match run {
189 Some(pt::Statement::VariableDefinition(
190 _,
191 _,
192 Some(pt::Expression::FunctionCall(_, _, args)),
193 )) => {
194 Some(args.first().unwrap())
198 }
199 _ => None,
200 }
201 }
202
203 async fn build_runner(&mut self, final_pc: usize) -> Result<ChiselRunner> {
204 let env = self.config.evm_opts.evm_env().await?;
205
206 let backend = match self.config.backend.clone() {
207 Some(backend) => backend,
208 None => {
209 let fork = self.config.evm_opts.get_fork(&self.config.foundry_config, env.clone());
210 let backend = Backend::spawn(fork)?;
211 self.config.backend = Some(backend.clone());
212 backend
213 }
214 };
215
216 let executor = ExecutorBuilder::new()
217 .inspectors(|stack| {
218 stack.chisel_state(final_pc).trace_mode(TraceMode::Call).cheatcodes(
219 CheatsConfig::new(
220 &self.config.foundry_config,
221 self.config.evm_opts.clone(),
222 None,
223 None,
224 )
225 .into(),
226 )
227 })
228 .gas_limit(self.config.evm_opts.gas_limit())
229 .spec_id(self.config.foundry_config.evm_spec_id())
230 .legacy_assertions(self.config.foundry_config.legacy_assertions)
231 .build(env, backend);
232
233 Ok(ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone()))
234 }
235}
236
237fn format_token(token: DynSolValue) -> String {
240 match token {
241 DynSolValue::Address(a) => {
242 format!("Type: {}\n└ Data: {}", "address".red(), a.cyan())
243 }
244 DynSolValue::FixedBytes(b, byte_len) => {
245 format!(
246 "Type: {}\n└ Data: {}",
247 format!("bytes{byte_len}").red(),
248 hex::encode_prefixed(b).cyan()
249 )
250 }
251 DynSolValue::Int(i, bit_len) => {
252 format!(
253 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
254 format!("int{bit_len}").red(),
255 format!(
256 "0x{}",
257 format!("{i:x}")
258 .chars()
259 .skip(if i.is_negative() { 64 - bit_len / 4 } else { 0 })
260 .collect::<String>()
261 )
262 .cyan(),
263 hex::encode_prefixed(B256::from(i)).cyan(),
264 i.cyan()
265 )
266 }
267 DynSolValue::Uint(i, bit_len) => {
268 format!(
269 "Type: {}\n├ Hex: {}\n├ Hex (full word): {}\n└ Decimal: {}",
270 format!("uint{bit_len}").red(),
271 format!("0x{i:x}").cyan(),
272 hex::encode_prefixed(B256::from(i)).cyan(),
273 i.cyan()
274 )
275 }
276 DynSolValue::Bool(b) => {
277 format!("Type: {}\n└ Value: {}", "bool".red(), b.cyan())
278 }
279 DynSolValue::String(_) | DynSolValue::Bytes(_) => {
280 let hex = hex::encode(token.abi_encode());
281 let s = token.as_str();
282 format!(
283 "Type: {}\n{}├ Hex (Memory):\n├─ Length ({}): {}\n├─ Contents ({}): {}\n├ Hex (Tuple Encoded):\n├─ Pointer ({}): {}\n├─ Length ({}): {}\n└─ Contents ({}): {}",
284 if s.is_some() { "string" } else { "dynamic bytes" }.red(),
285 if let Some(s) = s {
286 format!("├ UTF-8: {}\n", s.cyan())
287 } else {
288 String::default()
289 },
290 "[0x00:0x20]".yellow(),
291 format!("0x{}", &hex[64..128]).cyan(),
292 "[0x20:..]".yellow(),
293 format!("0x{}", &hex[128..]).cyan(),
294 "[0x00:0x20]".yellow(),
295 format!("0x{}", &hex[..64]).cyan(),
296 "[0x20:0x40]".yellow(),
297 format!("0x{}", &hex[64..128]).cyan(),
298 "[0x40:..]".yellow(),
299 format!("0x{}", &hex[128..]).cyan(),
300 )
301 }
302 DynSolValue::FixedArray(tokens) | DynSolValue::Array(tokens) => {
303 let mut out = format!(
304 "{}({}) = {}",
305 "array".red(),
306 format!("{}", tokens.len()).yellow(),
307 '['.red()
308 );
309 for token in tokens {
310 out.push_str("\n ├ ");
311 out.push_str(&format_token(token).replace('\n', "\n "));
312 out.push('\n');
313 }
314 out.push_str(&']'.red().to_string());
315 out
316 }
317 DynSolValue::Tuple(tokens) => {
318 let displayed_types = tokens
319 .iter()
320 .map(|t| t.sol_type_name().unwrap_or_default())
321 .collect::<Vec<_>>()
322 .join(", ");
323 let mut out =
324 format!("{}({}) = {}", "tuple".red(), displayed_types.yellow(), '('.red());
325 for token in tokens {
326 out.push_str("\n ├ ");
327 out.push_str(&format_token(token).replace('\n', "\n "));
328 out.push('\n');
329 }
330 out.push_str(&')'.red().to_string());
331 out
332 }
333 _ => {
334 unimplemented!()
335 }
336 }
337}
338
339fn format_event_definition(event_definition: &pt::EventDefinition) -> Result<String> {
350 let event_name = event_definition.name.as_ref().expect("Event has a name").to_string();
351 let inputs = event_definition
352 .fields
353 .iter()
354 .map(|param| {
355 let name = param
356 .name
357 .as_ref()
358 .map(ToString::to_string)
359 .unwrap_or_else(|| "<anonymous>".to_string());
360 let kind = Type::from_expression(¶m.ty)
361 .and_then(Type::into_builtin)
362 .ok_or_else(|| eyre::eyre!("Invalid type in event {event_name}"))?;
363 Ok(EventParam {
364 name,
365 ty: kind.to_string(),
366 components: vec![],
367 indexed: param.indexed,
368 internal_type: None,
369 })
370 })
371 .collect::<Result<Vec<_>>>()?;
372 let event =
373 alloy_json_abi::Event { name: event_name, inputs, anonymous: event_definition.anonymous };
374
375 Ok(format!(
376 "Type: {}\n├ Name: {}\n├ Signature: {:?}\n└ Selector: {:?}",
377 "event".red(),
378 SolidityHelper::new().highlight(&format!(
379 "{}({})",
380 &event.name,
381 &event
382 .inputs
383 .iter()
384 .map(|param| format!(
385 "{}{}{}",
386 param.ty,
387 if param.indexed { " indexed" } else { "" },
388 if param.name.is_empty() {
389 String::default()
390 } else {
391 format!(" {}", ¶m.name)
392 },
393 ))
394 .collect::<Vec<_>>()
395 .join(", ")
396 )),
397 event.signature().cyan(),
398 event.selector().cyan(),
399 ))
400}
401
402#[derive(Clone, Debug, PartialEq)]
408enum Type {
409 Builtin(DynSolType),
411
412 Array(Box<Self>),
414
415 FixedArray(Box<Self>, usize),
417
418 ArrayIndex(Box<Self>, Option<usize>),
420
421 Tuple(Vec<Option<Self>>),
423
424 Function(Box<Self>, Vec<Option<Self>>, Vec<Option<Self>>),
426
427 Access(Box<Self>, String),
429
430 Custom(Vec<String>),
432}
433
434impl Type {
435 fn from_expression(expr: &pt::Expression) -> Option<Self> {
445 match expr {
446 pt::Expression::Type(_, ty) => Self::from_type(ty),
447
448 pt::Expression::Variable(ident) => Some(Self::Custom(vec![ident.name.clone()])),
449
450 pt::Expression::ArraySubscript(_, expr, num) => {
452 Self::from_expression(expr).and_then(|ty| {
455 let boxed = Box::new(ty);
456 let num = num.as_deref().and_then(parse_number_literal).and_then(|n| {
457 usize::try_from(n).ok()
458 });
459 match expr.as_ref() {
460 pt::Expression::Type(_, _) => {
462 if let Some(num) = num {
463 Some(Self::FixedArray(boxed, num))
464 } else {
465 Some(Self::Array(boxed))
466 }
467 }
468 pt::Expression::Variable(_) => {
470 Some(Self::ArrayIndex(boxed, num))
471 }
472 _ => None
473 }
474 })
475 }
476 pt::Expression::ArrayLiteral(_, values) => {
477 values.first().and_then(Self::from_expression).map(|ty| {
478 Self::FixedArray(Box::new(ty), values.len())
479 })
480 }
481
482 pt::Expression::List(_, params) => Some(Self::Tuple(map_parameters(params))),
484
485 pt::Expression::MemberAccess(_, lhs, rhs) => {
487 Self::from_expression(lhs).map(|lhs| {
488 Self::Access(Box::new(lhs), rhs.name.clone())
489 })
490 }
491
492 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),
516
517 pt::Expression::ConditionalOperator(_, _, if_true, if_false) => {
519 Self::from_expression(if_true).or_else(|| Self::from_expression(if_false))
520 }
521
522 pt::Expression::AddressLiteral(_, _) => Some(Self::Builtin(DynSolType::Address)),
524 pt::Expression::HexNumberLiteral(_, s, _) => {
525 match s.parse::<Address>() {
526 Ok(addr) => {
527 if *s == addr.to_checksum(None) {
528 Some(Self::Builtin(DynSolType::Address))
529 } else {
530 Some(Self::Builtin(DynSolType::Uint(256)))
531 }
532 },
533 _ => {
534 Some(Self::Builtin(DynSolType::Uint(256)))
535 }
536 }
537 }
538
539 pt::Expression::Negate(_, inner) => Self::from_expression(inner).map(Self::invert_int),
542
543 pt::Expression::Add(_, lhs, rhs) |
547 pt::Expression::Subtract(_, lhs, rhs) |
548 pt::Expression::Multiply(_, lhs, rhs) |
549 pt::Expression::Divide(_, lhs, rhs) => {
550 match (Self::ethabi(lhs, None), Self::ethabi(rhs, None)) {
551 (Some(DynSolType::Int(_)), Some(DynSolType::Int(_))) |
552 (Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) |
553 (Some(DynSolType::Uint(_)), Some(DynSolType::Int(_))) => {
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 match &self {
673 Self::Access(inner, access) => {
674 if let Some(ty) = inner.as_ref().clone().try_as_ethabi(None) {
675 let ty = Self::Builtin(ty);
677 match access.as_str() {
678 "length" if ty.is_dynamic() || ty.is_array() || ty.is_fixed_bytes() => {
679 return Self::Builtin(DynSolType::Uint(256));
680 }
681 "pop" if ty.is_dynamic_array() => return ty,
682 _ => {}
683 }
684 }
685 }
686 _ => {}
687 }
688
689 let this = {
690 let name = types.last().unwrap().as_str();
691 match len {
692 0 => unreachable!(),
693 1 => match name {
694 "gasleft" | "addmod" | "mulmod" => Some(DynSolType::Uint(256)),
695 "keccak256" | "sha256" | "blockhash" => Some(DynSolType::FixedBytes(32)),
696 "ripemd160" => Some(DynSolType::FixedBytes(20)),
697 "ecrecover" => Some(DynSolType::Address),
698 _ => None,
699 },
700 2 => {
701 let access = types.first().unwrap().as_str();
702 match name {
703 "block" => match access {
704 "coinbase" => Some(DynSolType::Address),
705 "timestamp" | "difficulty" | "prevrandao" | "number" | "gaslimit"
706 | "chainid" | "basefee" | "blobbasefee" => Some(DynSolType::Uint(256)),
707 _ => None,
708 },
709 "msg" => match access {
710 "sender" => Some(DynSolType::Address),
711 "gas" => Some(DynSolType::Uint(256)),
712 "value" => Some(DynSolType::Uint(256)),
713 "data" => Some(DynSolType::Bytes),
714 "sig" => Some(DynSolType::FixedBytes(4)),
715 _ => None,
716 },
717 "tx" => match access {
718 "origin" => Some(DynSolType::Address),
719 "gasprice" => Some(DynSolType::Uint(256)),
720 _ => None,
721 },
722 "abi" => match access {
723 "decode" => {
724 let mut args = args.unwrap();
728 let last = args.pop().unwrap();
729 match last {
730 Some(ty) => {
731 return match ty {
732 Self::Tuple(_) => ty,
733 ty => Self::Tuple(vec![Some(ty)]),
734 };
735 }
736 None => None,
737 }
738 }
739 s if s.starts_with("encode") => Some(DynSolType::Bytes),
740 _ => None,
741 },
742 "address" => match access {
743 "balance" => Some(DynSolType::Uint(256)),
744 "code" => Some(DynSolType::Bytes),
745 "codehash" => Some(DynSolType::FixedBytes(32)),
746 "send" => Some(DynSolType::Bool),
747 _ => None,
748 },
749 "type" => match access {
750 "name" => Some(DynSolType::String),
751 "creationCode" | "runtimeCode" => Some(DynSolType::Bytes),
752 "interfaceId" => Some(DynSolType::FixedBytes(4)),
753 "min" | "max" => Some(
754 (|| args?.pop()??.into_builtin())()
756 .unwrap_or(DynSolType::Uint(256)),
757 ),
758 _ => None,
759 },
760 "string" => match access {
761 "concat" => Some(DynSolType::String),
762 _ => None,
763 },
764 "bytes" => match access {
765 "concat" => Some(DynSolType::Bytes),
766 _ => None,
767 },
768 _ => None,
769 }
770 }
771 _ => None,
772 }
773 };
774
775 this.map(Self::Builtin).unwrap_or_else(|| match types.last().unwrap().as_str() {
776 "this" | "super" => Self::Custom(types),
777 _ => match self {
778 Self::Custom(_) | Self::Access(_, _) => Self::Custom(types),
779 Self::Function(_, _, _) => self,
780 _ => unreachable!(),
781 },
782 })
783 }
784
785 fn recurse(&self, types: &mut Vec<String>, args: &mut Option<Vec<Option<Self>>>) {
788 match self {
789 Self::Builtin(ty) => types.push(ty.to_string()),
790 Self::Custom(tys) => types.extend(tys.clone()),
791 Self::Access(expr, name) => {
792 types.push(name.clone());
793 expr.recurse(types, args);
794 }
795 Self::Function(fn_name, fn_args, _fn_ret) => {
796 if args.is_none() && !fn_args.is_empty() {
797 *args = Some(fn_args.clone());
798 }
799 fn_name.recurse(types, args);
800 }
801 _ => {}
802 }
803 }
804
805 fn infer_custom_type(
819 intermediate: &IntermediateOutput,
820 custom_type: &mut Vec<String>,
821 contract_name: Option<String>,
822 ) -> Result<Option<DynSolType>> {
823 if let Some("this") | Some("super") = custom_type.last().map(String::as_str) {
824 custom_type.pop();
825 }
826 if custom_type.is_empty() {
827 return Ok(None);
828 }
829
830 if let Some(contract_name) = contract_name {
833 let intermediate_contract = intermediate
834 .intermediate_contracts
835 .get(&contract_name)
836 .ok_or_else(|| eyre::eyre!("Could not find intermediate contract!"))?;
837
838 let cur_type = custom_type.last().unwrap();
839 if let Some(func) = intermediate_contract.function_definitions.get(cur_type) {
840 if let res @ Some(_) = func_members(func, custom_type) {
842 return Ok(res);
843 }
844
845 if func.returns.is_empty() {
848 eyre::bail!(
849 "This call expression does not return any values to inspect. Insert as statement."
850 )
851 }
852
853 let (_, param) = func.returns.first().unwrap();
855 let return_ty = ¶m.as_ref().unwrap().ty;
857
858 if let pt::Expression::Variable(ident) = return_ty {
862 custom_type.push(ident.name.clone());
863 return Self::infer_custom_type(intermediate, custom_type, Some(contract_name));
864 }
865
866 if let Some(pt::FunctionAttribute::Mutability(_mut)) = func
870 .attributes
871 .iter()
872 .find(|attr| matches!(attr, pt::FunctionAttribute::Mutability(_)))
873 {
874 if let pt::Mutability::Payable(_) = _mut {
875 eyre::bail!("This function mutates state. Insert as a statement.")
876 }
877 } else {
878 eyre::bail!("This function mutates state. Insert as a statement.")
879 }
880
881 Ok(Self::ethabi(return_ty, Some(intermediate)))
882 } else if let Some(var) = intermediate_contract.variable_definitions.get(cur_type) {
883 Self::infer_var_expr(&var.ty, Some(intermediate), custom_type)
884 } else if let Some(strukt) = intermediate_contract.struct_definitions.get(cur_type) {
885 let inner_types = strukt
886 .fields
887 .iter()
888 .map(|var| {
889 Self::ethabi(&var.ty, Some(intermediate))
890 .ok_or_else(|| eyre::eyre!("Struct `{cur_type}` has invalid fields"))
891 })
892 .collect::<Result<Vec<_>>>()?;
893 Ok(Some(DynSolType::Tuple(inner_types)))
894 } else {
895 eyre::bail!(
896 "Could not find any definition in contract \"{contract_name}\" for type: {custom_type:?}"
897 )
898 }
899 } else {
900 if let Ok(res) = Self::infer_custom_type(intermediate, custom_type, Some("REPL".into()))
903 {
904 return Ok(res);
905 }
906
907 let name = custom_type.last().unwrap();
910 let contract = intermediate.intermediate_contracts.get(name);
911 if contract.is_some() {
912 let contract_name = custom_type.pop();
913 return Self::infer_custom_type(intermediate, custom_type, contract_name);
914 }
915
916 let name = custom_type.last().unwrap();
918 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
919 return Self::infer_var_expr(expr, Some(intermediate), custom_type);
920 }
921
922 Ok(None)
925 }
926 }
927
928 fn infer_var_expr(
930 expr: &pt::Expression,
931 intermediate: Option<&IntermediateOutput>,
932 custom_type: &mut Vec<String>,
933 ) -> Result<Option<DynSolType>> {
934 let res = match &expr {
936 pt::Expression::Variable(ident) => {
938 let name = &ident.name;
939
940 if let Some(intermediate) = intermediate {
941 if let Some(expr) = intermediate.repl_contract_expressions.get(name) {
943 Self::infer_var_expr(expr, Some(intermediate), custom_type)
944 } else if intermediate.intermediate_contracts.contains_key(name) {
945 if custom_type.len() > 1 {
946 custom_type.pop();
948 Self::infer_custom_type(intermediate, custom_type, Some(name.clone()))
949 } else {
950 Ok(Some(DynSolType::Address))
952 }
953 } else {
954 Err(eyre::eyre!("Could not infer variable type"))
955 }
956 } else {
957 Ok(None)
958 }
959 }
960 ty => Ok(Self::ethabi(ty, intermediate)),
961 };
962 match res {
965 Ok(Some(ty)) => {
966 let box_ty = Box::new(Self::Builtin(ty.clone()));
967 let access = Self::Access(box_ty, custom_type.drain(..).next().unwrap_or_default());
968 if let Some(mapped) = access.map_special().try_as_ethabi(intermediate) {
969 Ok(Some(mapped))
970 } else {
971 Ok(Some(ty))
972 }
973 }
974 res => res,
975 }
976 }
977
978 fn try_as_ethabi(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
986 match self {
987 Self::Builtin(ty) => Some(ty),
988 Self::Tuple(types) => Some(DynSolType::Tuple(types_to_parameters(types, intermediate))),
989 Self::Array(inner) => match *inner {
990 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
991 _ => inner
992 .try_as_ethabi(intermediate)
993 .map(|inner| DynSolType::Array(Box::new(inner))),
994 },
995 Self::FixedArray(inner, size) => match *inner {
996 ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),
997 _ => inner
998 .try_as_ethabi(intermediate)
999 .map(|inner| DynSolType::FixedArray(Box::new(inner), size)),
1000 },
1001 ty @ Self::ArrayIndex(_, _) => ty.into_array_index(intermediate),
1002 Self::Function(ty, _, _) => ty.try_as_ethabi(intermediate),
1003 Self::Access(_, _) => None,
1005 Self::Custom(mut types) => {
1006 intermediate.and_then(|intermediate| {
1008 Self::infer_custom_type(intermediate, &mut types, None).ok().flatten()
1009 })
1010 }
1011 }
1012 }
1013
1014 fn ethabi(
1016 expr: &pt::Expression,
1017 intermediate: Option<&IntermediateOutput>,
1018 ) -> Option<DynSolType> {
1019 Self::from_expression(expr)
1020 .map(Self::map_special)
1021 .and_then(|ty| ty.try_as_ethabi(intermediate))
1022 }
1023
1024 fn get_function_return_type<'a>(
1026 contract_expr: Option<&'a pt::Expression>,
1027 intermediate: &IntermediateOutput,
1028 ) -> Option<(&'a pt::Expression, DynSolType)> {
1029 let function_call = match contract_expr? {
1030 pt::Expression::FunctionCall(_, function_call, _) => function_call,
1031 _ => return None,
1032 };
1033 let (contract_name, function_name) = match function_call.as_ref() {
1034 pt::Expression::MemberAccess(_, contract_name, function_name) => {
1035 (contract_name, function_name)
1036 }
1037 _ => return None,
1038 };
1039 let contract_name = match contract_name.as_ref() {
1040 pt::Expression::Variable(contract_name) => contract_name.to_owned(),
1041 _ => return None,
1042 };
1043
1044 let pt::Expression::Variable(contract_name) =
1045 intermediate.repl_contract_expressions.get(&contract_name.name)?
1046 else {
1047 return None;
1048 };
1049
1050 let contract = intermediate
1051 .intermediate_contracts
1052 .get(&contract_name.name)?
1053 .function_definitions
1054 .get(&function_name.name)?;
1055 let return_parameter = contract.as_ref().returns.first()?.to_owned().1?;
1056 Self::ethabi(&return_parameter.ty, Some(intermediate)).map(|p| (contract_expr.unwrap(), p))
1057 }
1058
1059 fn invert_int(self) -> Self {
1061 match self {
1062 Self::Builtin(DynSolType::Uint(n)) => Self::Builtin(DynSolType::Int(n)),
1063 Self::Builtin(DynSolType::Int(n)) => Self::Builtin(DynSolType::Uint(n)),
1064 x => x,
1065 }
1066 }
1067
1068 #[inline]
1070 fn into_builtin(self) -> Option<DynSolType> {
1071 match self {
1072 Self::Builtin(ty) => Some(ty),
1073 _ => None,
1074 }
1075 }
1076
1077 fn into_array_index(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {
1079 match self {
1080 Self::Array(inner) | Self::FixedArray(inner, _) | Self::ArrayIndex(inner, _) => {
1081 match inner.try_as_ethabi(intermediate) {
1082 Some(DynSolType::Array(inner)) | Some(DynSolType::FixedArray(inner, _)) => {
1083 Some(*inner)
1084 }
1085 Some(DynSolType::Bytes)
1086 | Some(DynSolType::String)
1087 | Some(DynSolType::FixedBytes(_)) => Some(DynSolType::FixedBytes(1)),
1088 ty => ty,
1089 }
1090 }
1091 _ => None,
1092 }
1093 }
1094
1095 #[inline]
1097 fn is_dynamic(&self) -> bool {
1098 match self {
1099 Self::Builtin(DynSolType::Bytes | DynSolType::String | DynSolType::Array(_)) => true,
1102 Self::Array(_) => true,
1103 _ => false,
1104 }
1105 }
1106
1107 #[inline]
1109 fn is_array(&self) -> bool {
1110 matches!(
1111 self,
1112 Self::Array(_)
1113 | Self::FixedArray(_, _)
1114 | Self::Builtin(DynSolType::Array(_))
1115 | Self::Builtin(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(_)) | Some(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.into_iter() {
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}