for_loop.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::sema::ast::Namespace;
  3. use crate::sema::expression::ExprContext;
  4. use crate::sema::symtable::{LoopScopes, Symtable};
  5. use crate::sema::yul::ast::{YulBlock, YulStatement};
  6. use crate::sema::yul::block::{process_statements, resolve_yul_block};
  7. use crate::sema::yul::functions::FunctionsTable;
  8. use crate::sema::yul::switch::resolve_condition;
  9. use solang_parser::{diagnostics::Diagnostic, pt};
  10. /// Resolve a for-loop statement
  11. /// Returns the resolved block and a bool to indicate if the next statement is reachable.
  12. pub(crate) fn resolve_for_loop(
  13. yul_for: &pt::YulFor,
  14. context: &ExprContext,
  15. reachable: bool,
  16. loop_scope: &mut LoopScopes,
  17. symtable: &mut Symtable,
  18. function_table: &mut FunctionsTable,
  19. ns: &mut Namespace,
  20. ) -> Result<(YulStatement, bool), ()> {
  21. symtable.new_scope();
  22. function_table.new_scope();
  23. let mut next_reachable = reachable;
  24. let resolved_init_block = resolve_for_init_block(
  25. &yul_for.init_block,
  26. context,
  27. next_reachable,
  28. loop_scope,
  29. symtable,
  30. function_table,
  31. ns,
  32. )?;
  33. next_reachable &= resolved_init_block.1;
  34. let resolved_cond =
  35. resolve_condition(&yul_for.condition, context, symtable, function_table, ns)?;
  36. loop_scope.new_scope();
  37. let resolved_exec_block = resolve_yul_block(
  38. &yul_for.execution_block.loc,
  39. &yul_for.execution_block.statements,
  40. context,
  41. next_reachable,
  42. loop_scope,
  43. function_table,
  44. symtable,
  45. ns,
  46. );
  47. next_reachable &= resolved_exec_block.1;
  48. loop_scope.leave_scope();
  49. let resolved_post_block = resolve_yul_block(
  50. &yul_for.post_block.loc,
  51. &yul_for.post_block.statements,
  52. context,
  53. next_reachable,
  54. loop_scope,
  55. function_table,
  56. symtable,
  57. ns,
  58. );
  59. symtable.leave_scope();
  60. function_table.leave_scope(ns);
  61. Ok((
  62. YulStatement::For {
  63. loc: yul_for.loc,
  64. reachable,
  65. init_block: resolved_init_block.0,
  66. condition: resolved_cond,
  67. post_block: resolved_post_block.0,
  68. execution_block: resolved_exec_block.0,
  69. },
  70. resolved_init_block.1,
  71. ))
  72. }
  73. /// Resolve for initialization block.
  74. /// Returns the resolved block and a bool to indicate if the next statement is reachable.
  75. fn resolve_for_init_block(
  76. init_block: &pt::YulBlock,
  77. context: &ExprContext,
  78. reachable: bool,
  79. loop_scope: &mut LoopScopes,
  80. symtable: &mut Symtable,
  81. function_table: &mut FunctionsTable,
  82. ns: &mut Namespace,
  83. ) -> Result<(YulBlock, bool), ()> {
  84. for item in &init_block.statements {
  85. if matches!(item, pt::YulStatement::FunctionDefinition(_)) {
  86. ns.diagnostics.push(Diagnostic::error(
  87. item.loc(),
  88. "function definitions are not allowed inside for-init block".to_string(),
  89. ));
  90. return Err(());
  91. }
  92. }
  93. let (body, next_reachable) = process_statements(
  94. &init_block.statements,
  95. context,
  96. reachable,
  97. symtable,
  98. loop_scope,
  99. function_table,
  100. ns,
  101. );
  102. Ok((
  103. YulBlock {
  104. loc: init_block.loc,
  105. reachable,
  106. next_reachable,
  107. body,
  108. },
  109. next_reachable,
  110. ))
  111. }