| 149 | } |
| 150 | |
| 151 | absl::optional<Expr> ExpandExistsOneMacro(MacroExprFactory& factory, |
| 152 | Expr& target, absl::Span<Expr> args) { |
| 153 | if (args.size() != 2) { |
| 154 | return factory.ReportError("exists_one() requires 2 arguments"); |
| 155 | } |
| 156 | if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) { |
| 157 | return factory.ReportErrorAt( |
| 158 | args[0], "exists_one() variable name must be a simple identifier"); |
| 159 | } |
| 160 | if (args[0].ident_expr().name() == kAccumulatorVariableName) { |
| 161 | return factory.ReportErrorAt( |
| 162 | args[1], absl::StrCat("exists_one() variable name cannot be ", |
| 163 | kAccumulatorVariableName)); |
| 164 | } |
| 165 | auto init = factory.NewIntConst(0); |
| 166 | auto condition = factory.NewBoolConst(true); |
| 167 | auto accu_ident = factory.NewAccuIdent(); |
| 168 | auto const_1 = factory.NewIntConst(1); |
| 169 | auto inc_step = factory.NewCall(CelOperator::ADD, std::move(accu_ident), |
| 170 | std::move(const_1)); |
| 171 | |
| 172 | auto step = factory.NewCall(CelOperator::CONDITIONAL, std::move(args[1]), |
| 173 | std::move(inc_step), factory.NewAccuIdent()); |
| 174 | accu_ident = factory.NewAccuIdent(); |
| 175 | auto result = factory.NewCall(CelOperator::EQUALS, std::move(accu_ident), |
| 176 | factory.NewIntConst(1)); |
| 177 | return factory.NewComprehension(args[0].ident_expr().name(), |
| 178 | std::move(target), factory.AccuVarName(), |
| 179 | std::move(init), std::move(condition), |
| 180 | std::move(step), std::move(result)); |
| 181 | } |
| 182 | |
| 183 | Macro MakeExistsOneMacro() { |
| 184 | auto status_or_macro = |
nothing calls this directly
no test coverage detected