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