| 130 | }; |
| 131 | |
| 132 | absl::Status TernaryStep::Evaluate(ExecutionFrame* frame) const { |
| 133 | // Must have 3 or more values on the stack. |
| 134 | if (!frame->value_stack().HasEnough(3)) { |
| 135 | return absl::Status(absl::StatusCode::kInternal, "Value stack underflow"); |
| 136 | } |
| 137 | |
| 138 | // Create Span object that contains input arguments to the function. |
| 139 | auto args = frame->value_stack().GetSpan(3); |
| 140 | |
| 141 | const auto& condition = args[kTernaryStepCondition]; |
| 142 | // As opposed to regular functions, ternary treats unknowns or errors on the |
| 143 | // condition (arg0) as blocking. If we get an error or unknown then we |
| 144 | // ignore the other arguments and forward the condition as the result. |
| 145 | if (frame->enable_unknowns()) { |
| 146 | // Check if unknown? |
| 147 | if (condition.IsUnknown()) { |
| 148 | frame->value_stack().Pop(2); |
| 149 | return absl::OkStatus(); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | if (condition.IsError()) { |
| 154 | frame->value_stack().Pop(2); |
| 155 | return absl::OkStatus(); |
| 156 | } |
| 157 | |
| 158 | cel::Value result; |
| 159 | if (!condition.IsBool()) { |
| 160 | result = cel::ErrorValue(CreateNoMatchingOverloadError(kTernary)); |
| 161 | } else if (condition.GetBool().NativeValue()) { |
| 162 | result = args[kTernaryStepTrue]; |
| 163 | } else { |
| 164 | result = args[kTernaryStepFalse]; |
| 165 | } |
| 166 | |
| 167 | frame->value_stack().PopAndPush(args.size(), std::move(result)); |
| 168 | |
| 169 | return absl::OkStatus(); |
| 170 | } |
| 171 | |
| 172 | } // namespace |
| 173 |
no test coverage detected