Editor/Prism/Compiler/Ir/IrValue.cs

A small immutable record struct representing a handle to an IR expression plus its resolved shader type. It provides helpers for constructing valid/invalid values, queries for validity, component count, const-ness, and an implicit conversion to the underlying IrExpr.

Reflection
using Editor.Prism.Core;

namespace Editor.Prism.Compiler.Ir;

/// <summary>
/// A handle to an IR expression and its resolved type. This is the currency nodes deal in:
/// <c>EmitContext</c> hands them <see cref="IrValue"/>s, they combine them, and they hand values back.
/// <para>
/// <see cref="Invalid"/> is the failure value. A node that could not produce a result returns it and
/// the compile continues — one broken node never aborts the whole graph.
/// </para>
/// </summary>
public readonly record struct IrValue( IrExpr Expr, ShaderType Type )
{
	/// <summary>The failure value. Every operation on it produces another invalid value.</summary>
	public static readonly IrValue Invalid = default;

	/// <summary>Wrap an expression, taking its own type.</summary>
	public static IrValue Of( IrExpr expr ) => expr is null ? Invalid : new IrValue( expr, expr.Type );

	/// <summary>Wrap an expression with an explicit type.</summary>
	public static IrValue Of( IrExpr expr, ShaderType type ) => expr is null ? Invalid : new IrValue( expr, type );

	/// <summary>True when this value refers to a real expression.</summary>
	public bool IsValid => Expr is not null;

	/// <summary>Component count of the value's type.</summary>
	public int Components => Type.Components;

	/// <summary>True when the value is a compile-time literal.</summary>
	public bool IsConstant => Expr is IrConst;

	/// <summary>The literal behind this value, when it is one.</summary>
	public bool TryGetConst( out ConstValue value )
	{
		if ( Expr is IrConst constant )
		{
			value = constant.Value;
			return true;
		}

		value = default;
		return false;
	}

	/// <summary>Implicitly unwrap to the underlying expression.</summary>
	public static implicit operator IrExpr( IrValue value ) => value.Expr;

	/// <inheritdoc/>
	public override string ToString() => IsValid ? $"{Type.Hlsl}:{Expr.GetType().Name}" : "<invalid>";
}