Skip to content

Commit

Permalink
Document arithmetic binary operation type rules.
Browse files Browse the repository at this point in the history
  • Loading branch information
jimblandy authored and JCapucho committed Sep 10, 2022
1 parent 7d0e984 commit eb6124e
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
39 changes: 39 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,45 @@ pub enum UnaryOperator {
}

/// Operation that can be applied on two values.
///
/// ## Arithmetic type rules
///
/// The arithmetic operations `Add`, `Subtract`, `Multiply`, `Divide`, and
/// `Modulo` can all be applied to [`Scalar`] types other than [`Bool`], or
/// [`Vector`]s thereof. Both operands must have the same type.
///
/// `Add` and `Subtract` can also be applied to [`Matrix`] values. Both operands
/// must have the same type.
///
/// `Multiply` supports additional cases:
///
/// - A [`Matrix`] or [`Vector`] can be multiplied by a scalar [`Float`],
/// either on the left or the right.
///
/// - A [`Matrix`] on the left can be multiplied by a [`Vector`] on the right
/// if the matrix has as many columns as the vector has components (`matCxR
/// * VecC`).
///
/// - A [`Vector`] on the left can be multiplied by a [`Matrix`] on the right
/// if the matrix has as many rows as the vector has components (`VecR *
/// matCxR`).
///
/// - Two matrices can be multiplied if the left operand has as many columns
/// as the right operand has rows (`matNxR * matCxN`).
///
/// In all the above `Multiply` cases, the byte widths of the underlying scalar
/// types of both operands must be the same.
///
/// Note that `Multiply` supports mixed vector and scalar operations directly,
/// whereas the other arithmetic operations require an explicit [`Splat`] for
/// mixed-type use.
///
/// [`Scalar`]: TypeInner::Scalar
/// [`Vector`]: TypeInner::Vector
/// [`Matrix`]: TypeInner::Matrix
/// [`Float`]: ScalarKind::Float
/// [`Bool`]: ScalarKind::Bool
/// [`Splat`]: Expression::Splat
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
Expand Down
9 changes: 7 additions & 2 deletions src/valid/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,16 +740,18 @@ impl super::Validator {
_ => false,
},
Bo::Multiply => {
let kind_match = match left_inner.scalar_kind() {
let kind_allowed = match left_inner.scalar_kind() {
Some(Sk::Uint | Sk::Sint | Sk::Float) => true,
Some(Sk::Bool) | None => false,
};
let types_match = match (left_inner, right_inner) {
// Straight scalar and mixed scalar/vector.
(&Ti::Scalar { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. })
| (&Ti::Vector { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. })
| (&Ti::Scalar { kind: kind1, .. }, &Ti::Vector { kind: kind2, .. }) => {
kind1 == kind2
}
// Scalar/matrix.
(
&Ti::Scalar {
kind: Sk::Float, ..
Expand All @@ -762,6 +764,7 @@ impl super::Validator {
kind: Sk::Float, ..
},
) => true,
// Vector/vector.
(
&Ti::Vector {
kind: kind1,
Expand All @@ -774,6 +777,7 @@ impl super::Validator {
..
},
) => kind1 == kind2 && size1 == size2,
// Matrix * vector.
(
&Ti::Matrix { columns, .. },
&Ti::Vector {
Expand All @@ -782,6 +786,7 @@ impl super::Validator {
..
},
) => columns == size,
// Vector * matrix.
(
&Ti::Vector {
kind: Sk::Float,
Expand All @@ -807,7 +812,7 @@ impl super::Validator {
| Ti::Matrix { width, .. } => width,
_ => 0,
};
kind_match && types_match && left_width == right_width
kind_allowed && types_match && left_width == right_width
}
Bo::Equal | Bo::NotEqual => left_inner.is_sized() && left_inner == right_inner,
Bo::Less | Bo::LessEqual | Bo::Greater | Bo::GreaterEqual => {
Expand Down

0 comments on commit eb6124e

Please sign in to comment.