[tint] Support sparse .def files

Have the templates handle language definition files with missing binary
and unary operators, no const-eval functions and no type conversion
defintions.

Bug: tint:1718
Change-Id: I62fcfa6d94987849044c4ee2055f55ae72359dfc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/150362
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/intrinsic/data/data.cc b/src/tint/lang/core/intrinsic/data/data.cc
index fa6d930..7c5e67c 100644
--- a/src/tint/lang/core/intrinsic/data/data.cc
+++ b/src/tint/lang/core/intrinsic/data/data.cc
@@ -4752,112 +4752,112 @@
 static_assert(TemplateNumberIndex::CanIndex(kTemplateNumbers),
               "TemplateNumberIndex is not large enough to index kTemplateNumbers");
 
-constexpr constant::Eval::Function kConstEvalFunctions[] = {
-  /* [0] */ &constant::Eval::abs,
-  /* [1] */ &constant::Eval::acos,
-  /* [2] */ &constant::Eval::acosh,
-  /* [3] */ &constant::Eval::all,
-  /* [4] */ &constant::Eval::any,
-  /* [5] */ &constant::Eval::asin,
-  /* [6] */ &constant::Eval::asinh,
-  /* [7] */ &constant::Eval::atan,
-  /* [8] */ &constant::Eval::atan2,
-  /* [9] */ &constant::Eval::atanh,
-  /* [10] */ &constant::Eval::ceil,
-  /* [11] */ &constant::Eval::clamp,
-  /* [12] */ &constant::Eval::cos,
-  /* [13] */ &constant::Eval::cosh,
-  /* [14] */ &constant::Eval::countLeadingZeros,
-  /* [15] */ &constant::Eval::countOneBits,
-  /* [16] */ &constant::Eval::countTrailingZeros,
-  /* [17] */ &constant::Eval::cross,
-  /* [18] */ &constant::Eval::degrees,
-  /* [19] */ &constant::Eval::determinant,
-  /* [20] */ &constant::Eval::distance,
-  /* [21] */ &constant::Eval::dot,
-  /* [22] */ &constant::Eval::exp,
-  /* [23] */ &constant::Eval::exp2,
-  /* [24] */ &constant::Eval::extractBits,
-  /* [25] */ &constant::Eval::faceForward,
-  /* [26] */ &constant::Eval::firstLeadingBit,
-  /* [27] */ &constant::Eval::firstTrailingBit,
-  /* [28] */ &constant::Eval::floor,
-  /* [29] */ &constant::Eval::fma,
-  /* [30] */ &constant::Eval::fract,
-  /* [31] */ &constant::Eval::frexp,
-  /* [32] */ &constant::Eval::insertBits,
-  /* [33] */ &constant::Eval::inverseSqrt,
-  /* [34] */ &constant::Eval::ldexp,
-  /* [35] */ &constant::Eval::length,
-  /* [36] */ &constant::Eval::log,
-  /* [37] */ &constant::Eval::log2,
-  /* [38] */ &constant::Eval::max,
-  /* [39] */ &constant::Eval::min,
-  /* [40] */ &constant::Eval::mix,
-  /* [41] */ &constant::Eval::modf,
-  /* [42] */ &constant::Eval::normalize,
-  /* [43] */ &constant::Eval::pack2x16float,
-  /* [44] */ &constant::Eval::pack2x16snorm,
-  /* [45] */ &constant::Eval::pack2x16unorm,
-  /* [46] */ &constant::Eval::pack4x8snorm,
-  /* [47] */ &constant::Eval::pack4x8unorm,
-  /* [48] */ &constant::Eval::pow,
-  /* [49] */ &constant::Eval::quantizeToF16,
-  /* [50] */ &constant::Eval::radians,
-  /* [51] */ &constant::Eval::reflect,
-  /* [52] */ &constant::Eval::refract,
-  /* [53] */ &constant::Eval::reverseBits,
-  /* [54] */ &constant::Eval::round,
-  /* [55] */ &constant::Eval::saturate,
-  /* [56] */ &constant::Eval::select_bool,
-  /* [57] */ &constant::Eval::select_boolvec,
-  /* [58] */ &constant::Eval::sign,
-  /* [59] */ &constant::Eval::sin,
-  /* [60] */ &constant::Eval::sinh,
-  /* [61] */ &constant::Eval::smoothstep,
-  /* [62] */ &constant::Eval::sqrt,
-  /* [63] */ &constant::Eval::step,
-  /* [64] */ &constant::Eval::tan,
-  /* [65] */ &constant::Eval::tanh,
-  /* [66] */ &constant::Eval::transpose,
-  /* [67] */ &constant::Eval::trunc,
-  /* [68] */ &constant::Eval::unpack2x16float,
-  /* [69] */ &constant::Eval::unpack2x16snorm,
-  /* [70] */ &constant::Eval::unpack2x16unorm,
-  /* [71] */ &constant::Eval::unpack4x8snorm,
-  /* [72] */ &constant::Eval::unpack4x8unorm,
-  /* [73] */ &constant::Eval::Identity,
-  /* [74] */ &constant::Eval::Not,
-  /* [75] */ &constant::Eval::Complement,
-  /* [76] */ &constant::Eval::UnaryMinus,
-  /* [77] */ &constant::Eval::Plus,
-  /* [78] */ &constant::Eval::Minus,
-  /* [79] */ &constant::Eval::Multiply,
-  /* [80] */ &constant::Eval::MultiplyMatVec,
-  /* [81] */ &constant::Eval::MultiplyVecMat,
-  /* [82] */ &constant::Eval::MultiplyMatMat,
-  /* [83] */ &constant::Eval::Divide,
-  /* [84] */ &constant::Eval::Modulo,
-  /* [85] */ &constant::Eval::Xor,
-  /* [86] */ &constant::Eval::And,
-  /* [87] */ &constant::Eval::Or,
-  /* [88] */ &constant::Eval::LogicalAnd,
-  /* [89] */ &constant::Eval::LogicalOr,
-  /* [90] */ &constant::Eval::Equal,
-  /* [91] */ &constant::Eval::NotEqual,
-  /* [92] */ &constant::Eval::LessThan,
-  /* [93] */ &constant::Eval::GreaterThan,
-  /* [94] */ &constant::Eval::LessThanEqual,
-  /* [95] */ &constant::Eval::GreaterThanEqual,
-  /* [96] */ &constant::Eval::ShiftLeft,
-  /* [97] */ &constant::Eval::ShiftRight,
-  /* [98] */ &constant::Eval::Zero,
-  /* [99] */ &constant::Eval::Conv,
-  /* [100] */ &constant::Eval::VecSplat,
-  /* [101] */ &constant::Eval::VecInitS,
-  /* [102] */ &constant::Eval::VecInitM,
-  /* [103] */ &constant::Eval::MatInitS,
-  /* [104] */ &constant::Eval::MatInitV,
+constexpr core::constant::Eval::Function kConstEvalFunctions[] = {
+  /* [0] */ &core::constant::Eval::abs,
+  /* [1] */ &core::constant::Eval::acos,
+  /* [2] */ &core::constant::Eval::acosh,
+  /* [3] */ &core::constant::Eval::all,
+  /* [4] */ &core::constant::Eval::any,
+  /* [5] */ &core::constant::Eval::asin,
+  /* [6] */ &core::constant::Eval::asinh,
+  /* [7] */ &core::constant::Eval::atan,
+  /* [8] */ &core::constant::Eval::atan2,
+  /* [9] */ &core::constant::Eval::atanh,
+  /* [10] */ &core::constant::Eval::ceil,
+  /* [11] */ &core::constant::Eval::clamp,
+  /* [12] */ &core::constant::Eval::cos,
+  /* [13] */ &core::constant::Eval::cosh,
+  /* [14] */ &core::constant::Eval::countLeadingZeros,
+  /* [15] */ &core::constant::Eval::countOneBits,
+  /* [16] */ &core::constant::Eval::countTrailingZeros,
+  /* [17] */ &core::constant::Eval::cross,
+  /* [18] */ &core::constant::Eval::degrees,
+  /* [19] */ &core::constant::Eval::determinant,
+  /* [20] */ &core::constant::Eval::distance,
+  /* [21] */ &core::constant::Eval::dot,
+  /* [22] */ &core::constant::Eval::exp,
+  /* [23] */ &core::constant::Eval::exp2,
+  /* [24] */ &core::constant::Eval::extractBits,
+  /* [25] */ &core::constant::Eval::faceForward,
+  /* [26] */ &core::constant::Eval::firstLeadingBit,
+  /* [27] */ &core::constant::Eval::firstTrailingBit,
+  /* [28] */ &core::constant::Eval::floor,
+  /* [29] */ &core::constant::Eval::fma,
+  /* [30] */ &core::constant::Eval::fract,
+  /* [31] */ &core::constant::Eval::frexp,
+  /* [32] */ &core::constant::Eval::insertBits,
+  /* [33] */ &core::constant::Eval::inverseSqrt,
+  /* [34] */ &core::constant::Eval::ldexp,
+  /* [35] */ &core::constant::Eval::length,
+  /* [36] */ &core::constant::Eval::log,
+  /* [37] */ &core::constant::Eval::log2,
+  /* [38] */ &core::constant::Eval::max,
+  /* [39] */ &core::constant::Eval::min,
+  /* [40] */ &core::constant::Eval::mix,
+  /* [41] */ &core::constant::Eval::modf,
+  /* [42] */ &core::constant::Eval::normalize,
+  /* [43] */ &core::constant::Eval::pack2x16float,
+  /* [44] */ &core::constant::Eval::pack2x16snorm,
+  /* [45] */ &core::constant::Eval::pack2x16unorm,
+  /* [46] */ &core::constant::Eval::pack4x8snorm,
+  /* [47] */ &core::constant::Eval::pack4x8unorm,
+  /* [48] */ &core::constant::Eval::pow,
+  /* [49] */ &core::constant::Eval::quantizeToF16,
+  /* [50] */ &core::constant::Eval::radians,
+  /* [51] */ &core::constant::Eval::reflect,
+  /* [52] */ &core::constant::Eval::refract,
+  /* [53] */ &core::constant::Eval::reverseBits,
+  /* [54] */ &core::constant::Eval::round,
+  /* [55] */ &core::constant::Eval::saturate,
+  /* [56] */ &core::constant::Eval::select_bool,
+  /* [57] */ &core::constant::Eval::select_boolvec,
+  /* [58] */ &core::constant::Eval::sign,
+  /* [59] */ &core::constant::Eval::sin,
+  /* [60] */ &core::constant::Eval::sinh,
+  /* [61] */ &core::constant::Eval::smoothstep,
+  /* [62] */ &core::constant::Eval::sqrt,
+  /* [63] */ &core::constant::Eval::step,
+  /* [64] */ &core::constant::Eval::tan,
+  /* [65] */ &core::constant::Eval::tanh,
+  /* [66] */ &core::constant::Eval::transpose,
+  /* [67] */ &core::constant::Eval::trunc,
+  /* [68] */ &core::constant::Eval::unpack2x16float,
+  /* [69] */ &core::constant::Eval::unpack2x16snorm,
+  /* [70] */ &core::constant::Eval::unpack2x16unorm,
+  /* [71] */ &core::constant::Eval::unpack4x8snorm,
+  /* [72] */ &core::constant::Eval::unpack4x8unorm,
+  /* [73] */ &core::constant::Eval::Identity,
+  /* [74] */ &core::constant::Eval::Not,
+  /* [75] */ &core::constant::Eval::Complement,
+  /* [76] */ &core::constant::Eval::UnaryMinus,
+  /* [77] */ &core::constant::Eval::Plus,
+  /* [78] */ &core::constant::Eval::Minus,
+  /* [79] */ &core::constant::Eval::Multiply,
+  /* [80] */ &core::constant::Eval::MultiplyMatVec,
+  /* [81] */ &core::constant::Eval::MultiplyVecMat,
+  /* [82] */ &core::constant::Eval::MultiplyMatMat,
+  /* [83] */ &core::constant::Eval::Divide,
+  /* [84] */ &core::constant::Eval::Modulo,
+  /* [85] */ &core::constant::Eval::Xor,
+  /* [86] */ &core::constant::Eval::And,
+  /* [87] */ &core::constant::Eval::Or,
+  /* [88] */ &core::constant::Eval::LogicalAnd,
+  /* [89] */ &core::constant::Eval::LogicalOr,
+  /* [90] */ &core::constant::Eval::Equal,
+  /* [91] */ &core::constant::Eval::NotEqual,
+  /* [92] */ &core::constant::Eval::LessThan,
+  /* [93] */ &core::constant::Eval::GreaterThan,
+  /* [94] */ &core::constant::Eval::LessThanEqual,
+  /* [95] */ &core::constant::Eval::GreaterThanEqual,
+  /* [96] */ &core::constant::Eval::ShiftLeft,
+  /* [97] */ &core::constant::Eval::ShiftRight,
+  /* [98] */ &core::constant::Eval::Zero,
+  /* [99] */ &core::constant::Eval::Conv,
+  /* [100] */ &core::constant::Eval::VecSplat,
+  /* [101] */ &core::constant::Eval::VecInitS,
+  /* [102] */ &core::constant::Eval::VecInitM,
+  /* [103] */ &core::constant::Eval::MatInitS,
+  /* [104] */ &core::constant::Eval::MatInitV,
 };
 
 static_assert(ConstEvalFunctionIndex::CanIndex(kConstEvalFunctions),
@@ -12214,27 +12214,27 @@
     /* const_eval_functions */ kConstEvalFunctions,
     /* ctor_conv */ kConstructorsAndConverters,
     /* builtins */ kBuiltins,
-    /* binary_plus */ kBinaryOperators[kBinaryOperatorPlus],
-    /* binary_minus */ kBinaryOperators[kBinaryOperatorMinus],
-    /* binary_star */ kBinaryOperators[kBinaryOperatorStar],
-    /* binary_divide */ kBinaryOperators[kBinaryOperatorDivide],
-    /* binary_modulo */ kBinaryOperators[kBinaryOperatorModulo],
-    /* binary_xor */ kBinaryOperators[kBinaryOperatorXor],
-    /* binary_and */ kBinaryOperators[kBinaryOperatorAnd],
-    /* binary_or */ kBinaryOperators[kBinaryOperatorOr],
-    /* binary_logical_and */ kBinaryOperators[kBinaryOperatorLogicalAnd],
-    /* binary_logical_or */ kBinaryOperators[kBinaryOperatorLogicalOr],
-    /* binary_equal */ kBinaryOperators[kBinaryOperatorEqual],
-    /* binary_not_equal */ kBinaryOperators[kBinaryOperatorNotEqual],
-    /* binary_less_than */ kBinaryOperators[kBinaryOperatorLessThan],
-    /* binary_greater_than */ kBinaryOperators[kBinaryOperatorGreaterThan],
-    /* binary_less_than_equal */ kBinaryOperators[kBinaryOperatorLessThanEqual],
-    /* binary_greater_than_equal */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
-    /* binary_shift_left */ kBinaryOperators[kBinaryOperatorShiftLeft],
-    /* binary_shift_right */ kBinaryOperators[kBinaryOperatorShiftRight],
-    /* unary_not */ kUnaryOperators[kUnaryOperatorNot],
-    /* unary_complement */ kUnaryOperators[kUnaryOperatorComplement],
-    /* unary_minus */ kUnaryOperators[kUnaryOperatorMinus],
+    /* binary '+' */ kBinaryOperators[kBinaryOperatorPlus],
+    /* binary '-' */ kBinaryOperators[kBinaryOperatorMinus],
+    /* binary '*' */ kBinaryOperators[kBinaryOperatorStar],
+    /* binary '/' */ kBinaryOperators[kBinaryOperatorDivide],
+    /* binary '%' */ kBinaryOperators[kBinaryOperatorModulo],
+    /* binary '^' */ kBinaryOperators[kBinaryOperatorXor],
+    /* binary '&' */ kBinaryOperators[kBinaryOperatorAnd],
+    /* binary '|' */ kBinaryOperators[kBinaryOperatorOr],
+    /* binary '&&' */ kBinaryOperators[kBinaryOperatorLogicalAnd],
+    /* binary '||' */ kBinaryOperators[kBinaryOperatorLogicalOr],
+    /* binary '==' */ kBinaryOperators[kBinaryOperatorEqual],
+    /* binary '!=' */ kBinaryOperators[kBinaryOperatorNotEqual],
+    /* binary '<' */ kBinaryOperators[kBinaryOperatorLessThan],
+    /* binary '>' */ kBinaryOperators[kBinaryOperatorGreaterThan],
+    /* binary '<=' */ kBinaryOperators[kBinaryOperatorLessThanEqual],
+    /* binary '>=' */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
+    /* binary '<<' */ kBinaryOperators[kBinaryOperatorShiftLeft],
+    /* binary '>>' */ kBinaryOperators[kBinaryOperatorShiftRight],
+    /* unary '!' */ kUnaryOperators[kUnaryOperatorNot],
+    /* unary '~' */ kUnaryOperators[kUnaryOperatorComplement],
+    /* unary '-' */ kUnaryOperators[kUnaryOperatorMinus],
 };
 
 }  // namespace tint::core::intrinsic::data
diff --git a/src/tint/lang/core/intrinsic/table_data.h b/src/tint/lang/core/intrinsic/table_data.h
index baea171..5d540aa 100644
--- a/src/tint/lang/core/intrinsic/table_data.h
+++ b/src/tint/lang/core/intrinsic/table_data.h
@@ -208,6 +208,9 @@
     const OverloadIndex overloads;
 };
 
+/// A IntrinsicInfo with no overloads
+static constexpr IntrinsicInfo kNoOverloads{0, OverloadIndex(OverloadIndex::kInvalid)};
+
 /// Number is an 32 bit unsigned integer, which can be in one of three states:
 /// * Invalid - Number has not been assigned a value
 /// * Valid   - a fixed integer value
diff --git a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
index 8326ad6..ae10629 100644
--- a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
+++ b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
@@ -136,14 +136,17 @@
 static_assert(TemplateNumberIndex::CanIndex(kTemplateNumbers),
               "TemplateNumberIndex is not large enough to index kTemplateNumbers");
 
-constexpr constant::Eval::Function kConstEvalFunctions[] = {
-{{- range $i, $f := .ConstEvalFunctions }}
-  /* [{{$i}}] */ &constant::Eval::{{template "ExpandName" $f}},
-{{- end }}
+{{- if .ConstEvalFunctions}}
+{{/* newline */}}
+constexpr core::constant::Eval::Function kConstEvalFunctions[] = {
+{{-   range $i, $f := .ConstEvalFunctions }}
+  /* [{{$i}}] */ &core::constant::Eval::{{template "OperatorName" $f}},
+{{-   end }}
 };
 
 static_assert(ConstEvalFunctionIndex::CanIndex(kConstEvalFunctions),
               "ConstEvalFunctionIndex is not large enough to index kConstEvalFunctions");
+{{- end}}
 
 constexpr OverloadInfo kOverloads[] = {
 {{- range $i, $o := .Overloads }}
@@ -203,52 +206,65 @@
 {{- end }}
 };
 
+{{- if .UnaryOperators}}
+{{/* newline */}}
 constexpr IntrinsicInfo kUnaryOperators[] = {
-{{- range $i, $o := .UnaryOperators }}
+{{-   range $i, $o := .UnaryOperators }}
   {
     /* [{{$i}}] */
-{{-   range $o.OverloadDescriptions }}
+{{-     range $o.OverloadDescriptions }}
     /* {{.}} */
-{{-   end }}
+{{-     end }}
     /* num overloads */ {{$o.NumOverloads}},
     /* overloads */ OverloadIndex({{$o.OverloadsOffset}}),
   },
-{{- end }}
+{{-   end }}
 };
-
-{{- range $i, $o := .UnaryOperators }}
-constexpr uint8_t kUnaryOperator{{ template "ExpandName" $o.Name}} = {{$i}};
 {{- end }}
 
+{{- $unary_ops := Map }}
+{{- range $i, $o := .UnaryOperators }}
+{{-   $unary_ops.Put $o.Name true }}
+constexpr uint8_t kUnaryOperator{{ template "OperatorName" $o.Name}} = {{$i}};
+{{- end }}
+
+{{- if .BinaryOperators}}
+{{/* newline */}}
 constexpr IntrinsicInfo kBinaryOperators[] = {
-{{- range $i, $o := .BinaryOperators }}
+{{-   range $i, $o := .BinaryOperators }}
   {
     /* [{{$i}}] */
-{{-   range $o.OverloadDescriptions }}
+{{-     range $o.OverloadDescriptions }}
     /* {{.}} */
-{{-   end }}
+{{-     end }}
     /* num overloads */ {{$o.NumOverloads}},
     /* overloads */ OverloadIndex({{$o.OverloadsOffset}}),
   },
-{{- end }}
+{{-   end }}
 };
-
-{{- range $i, $o := .BinaryOperators }}
-constexpr uint8_t kBinaryOperator{{ template "ExpandName" $o.Name}} = {{$i}};
 {{- end }}
 
+{{- $bin_ops := Map }}
+{{- range $i, $o := .BinaryOperators }}
+{{-   $bin_ops.Put $o.Name true }}
+constexpr uint8_t kBinaryOperator{{ template "OperatorName" $o.Name}} = {{$i}};
+{{- end }}
+
+{{- if .ConstructorsAndConverters}}
+{{/* newline */}}
 constexpr IntrinsicInfo kConstructorsAndConverters[] = {
-{{- range $i, $o := .ConstructorsAndConverters }}
+{{-   range $i, $o := .ConstructorsAndConverters }}
   {
     /* [{{$i}}] */
-{{-   range $o.OverloadDescriptions }}
+{{-     range $o.OverloadDescriptions }}
     /* {{.}} */
-{{-   end }}
+{{-     end }}
     /* num overloads */ {{$o.NumOverloads}},
     /* overloads */ OverloadIndex({{$o.OverloadsOffset}}),
   },
-{{- end }}
+{{-   end }}
 };
+{{- end }}
 
 // clang-format on
 
@@ -263,30 +279,17 @@
   /* number_matchers */ kNumberMatchers,
   /* parameters */ kParameters,
   /* overloads */ kOverloads,
-  /* const_eval_functions */ kConstEvalFunctions,
-  /* ctor_conv */ kConstructorsAndConverters,
+  /* const_eval_functions */ {{if .ConstEvalFunctions}}kConstEvalFunctions{{else}}Empty{{end}},
+  /* ctor_conv */ {{if .ConstructorsAndConverters}}kConstructorsAndConverters{{else}}Empty{{end}},
   /* builtins */ kBuiltins,
-  /* binary_plus */ kBinaryOperators[kBinaryOperatorPlus],
-  /* binary_minus */ kBinaryOperators[kBinaryOperatorMinus],
-  /* binary_star */ kBinaryOperators[kBinaryOperatorStar],
-  /* binary_divide */ kBinaryOperators[kBinaryOperatorDivide],
-  /* binary_modulo */ kBinaryOperators[kBinaryOperatorModulo],
-  /* binary_xor */ kBinaryOperators[kBinaryOperatorXor],
-  /* binary_and */ kBinaryOperators[kBinaryOperatorAnd],
-  /* binary_or */ kBinaryOperators[kBinaryOperatorOr],
-  /* binary_logical_and */ kBinaryOperators[kBinaryOperatorLogicalAnd],
-  /* binary_logical_or */ kBinaryOperators[kBinaryOperatorLogicalOr],
-  /* binary_equal */ kBinaryOperators[kBinaryOperatorEqual],
-  /* binary_not_equal */ kBinaryOperators[kBinaryOperatorNotEqual],
-  /* binary_less_than */ kBinaryOperators[kBinaryOperatorLessThan],
-  /* binary_greater_than */ kBinaryOperators[kBinaryOperatorGreaterThan],
-  /* binary_less_than_equal */ kBinaryOperators[kBinaryOperatorLessThanEqual],
-  /* binary_greater_than_equal */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
-  /* binary_shift_left */ kBinaryOperators[kBinaryOperatorShiftLeft],
-  /* binary_shift_right */ kBinaryOperators[kBinaryOperatorShiftRight],
-  /* unary_not */ kUnaryOperators[kUnaryOperatorNot],
-  /* unary_complement */ kUnaryOperators[kUnaryOperatorComplement],
-  /* unary_minus */ kUnaryOperators[kUnaryOperatorMinus],
+{{- range $op := List "+" "-" "*" "/" "%" "^" "&" "|" "&&" "||" "==" "!=" "<" ">" "<=" ">=" "<<" ">>"}}
+{{-   $N := Eval "OperatorName" $op }}
+  /* binary '{{$op}}' */ {{if $bin_ops.Get .}}kBinaryOperators[kBinaryOperator{{$N}}]{{else}}tint::core::intrinsic::kNoOverloads{{end}},
+{{- end}}
+{{- range $op := List "!" "~" "-"}}
+{{-   $N := Eval "OperatorName" $op }}
+  /* unary '{{$op}}' */ {{if $unary_ops.Get .}}kUnaryOperators[kUnaryOperator{{$N}}]{{else}}tint::core::intrinsic::kNoOverloads{{end}},
+{{- end}}
 };
 
 {{  end -}}
@@ -520,7 +523,7 @@
 
 
 {{- /* ------------------------------------------------------------------ */ -}}
-{{-                           define "ExpandName"                            -}}
+{{-                          define "OperatorName"                           -}}
 {{- /* ------------------------------------------------------------------ */ -}}
 {{-        if eq . "<<" -}}ShiftLeft
 {{-   else if eq . "&"  -}}And
diff --git a/tools/src/template/template.go b/tools/src/template/template.go
index e3adeff..5be9be5 100644
--- a/tools/src/template/template.go
+++ b/tools/src/template/template.go
@@ -73,6 +73,7 @@
 		"HasSuffix":  strings.HasSuffix,
 		"Import":     g.importTmpl,
 		"Iterate":    iterate,
+		"List":       list,
 		"Map":        newMap,
 		"PascalCase": pascalCase,
 		"ToUpper":    strings.ToUpper,
@@ -197,6 +198,10 @@
 	return out
 }
 
+// list returns a new slice of elements from the argument list
+// Useful for: {{- range Slice "a" "b" "c" -}}{{.}}{{end}}
+func list(elements ...any) []any { return elements }
+
 // pascalCase returns the snake-case string s transformed into 'PascalCase',
 // Rules:
 // * The first letter of the string is capitalized