Processes `pending` binary ops from innermost to outermost, using `reg` as the accumulator. This avoids the deep recursion that would arise if we compiled binary op chains by recursing on the lhs.
(
codegen: &mut Codegen,
symtable: &mut TempSymtable<'_, '_>,
reg: Register,
mut etype: ExprType,
mut pending: Vec<PendingOp>,
)
| 450 | /// This avoids the deep recursion that would arise if we compiled binary op chains |
| 451 | /// by recursing on the lhs. |
| 452 | fn compile_pending_ops( |
| 453 | codegen: &mut Codegen, |
| 454 | symtable: &mut TempSymtable<'_, '_>, |
| 455 | reg: Register, |
| 456 | mut etype: ExprType, |
| 457 | mut pending: Vec<PendingOp>, |
| 458 | ) -> Result<ExprType> { |
| 459 | while let Some(op) = pending.pop() { |
| 460 | match op { |
| 461 | PendingOp::Unary(op) => { |
| 462 | let result_type = match etype { |
| 463 | ExprType::Boolean if op.make_boolean.is_some() => ExprType::Boolean, |
| 464 | ExprType::Double if op.make_double.is_some() => ExprType::Double, |
| 465 | ExprType::Integer => ExprType::Integer, |
| 466 | _ => match op.kind { |
| 467 | PendingUnaryKind::Negate => return Err(Error::NotANumber(op.pos, etype)), |
| 468 | PendingUnaryKind::Not => { |
| 469 | return Err(Error::TypeMismatch(op.pos, etype, ExprType::Integer)); |
| 470 | } |
| 471 | }, |
| 472 | }; |
| 473 | match result_type { |
| 474 | ExprType::Boolean => { |
| 475 | let mut scope = symtable.temp_scope(); |
| 476 | let temp = scope.alloc().map_err(|e| Error::from_syms(e, op.pos))?; |
| 477 | codegen.emit_value(temp, ConstantDatum::Integer(1), op.pos)?; |
| 478 | codegen.emit(op.make_boolean.unwrap()(reg, reg, temp), op.pos); |
| 479 | } |
| 480 | ExprType::Double => { |
| 481 | codegen.emit(op.make_double.unwrap()(reg), op.pos); |
| 482 | } |
| 483 | ExprType::Integer => { |
| 484 | codegen.emit((op.make_integer)(reg), op.pos); |
| 485 | } |
| 486 | ExprType::Text => unreachable!(), |
| 487 | } |
| 488 | etype = result_type; |
| 489 | } |
| 490 | PendingOp::Binary(op) => { |
| 491 | let rpos = op.rhs.start_pos(); |
| 492 | let mut scope = symtable.temp_scope(); |
| 493 | let rtemp = scope.alloc().map_err(|e| Error::from_syms(e, rpos))?; |
| 494 | let rtype = compile_expr(codegen, symtable, rtemp, op.rhs)?; |
| 495 | |
| 496 | let result_type = match (etype, rtype) { |
| 497 | (ExprType::Boolean, ExprType::Boolean) if op.make_boolean.is_some() => { |
| 498 | ExprType::Boolean |
| 499 | } |
| 500 | (ExprType::Text, ExprType::Text) if op.make_text.is_some() => ExprType::Text, |
| 501 | (_, _) if op.make_double.is_some() => { |
| 502 | match resolve_numeric_binary_type( |
| 503 | codegen, reg, etype, rtemp, rtype, rpos, op.pos, |
| 504 | ) { |
| 505 | Some(v) => v, |
| 506 | None => { |
| 507 | return Err(Error::BinaryOpType(op.pos, op.op_name, etype, rtype)); |
| 508 | } |
| 509 | } |
no test coverage detected