Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 1 | {{- /* |
| 2 | -------------------------------------------------------------------------------- |
| 3 | Template file for use with tools/builtin-gen to generate builtin_table.inl |
| 4 | Used by BuiltinTable.cc for builtin overload resolution. |
| 5 | |
| 6 | See: |
Ben Clayton | e132516 | 2022-05-06 15:13:01 +0000 | [diff] [blame] | 7 | * tools/cmd/intrinsic-gen/gen for structures used by this template |
Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 8 | * https://golang.org/pkg/text/template/ for documentation on the template syntax |
| 9 | -------------------------------------------------------------------------------- |
| 10 | */ -}} |
| 11 | |
| 12 | // clang-format off |
| 13 | |
| 14 | {{ with .Sem -}} |
| 15 | {{ range .Types -}} |
| 16 | {{ template "Type" . }} |
| 17 | {{ end -}} |
| 18 | {{ range .TypeMatchers -}} |
| 19 | {{ template "TypeMatcher" . }} |
| 20 | {{ end -}} |
| 21 | {{ range .EnumMatchers -}} |
| 22 | {{ template "EnumMatcher" . }} |
| 23 | {{ end -}} |
| 24 | {{- end -}} |
| 25 | |
Ben Clayton | e6e96de | 2022-05-09 18:08:23 +0000 | [diff] [blame] | 26 | {{- with IntrinsicTable -}} |
Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 27 | {{- template "Matchers" . }} |
| 28 | |
| 29 | constexpr MatcherIndex kMatcherIndices[] = { |
| 30 | {{- range $i, $idx := .MatcherIndices }} |
| 31 | /* [{{$i}}] */ {{$idx}}, |
| 32 | {{- end }} |
| 33 | }; |
| 34 | |
| 35 | // Assert that the MatcherIndex is big enough to index all the matchers, plus |
| 36 | // kNoMatcher. |
| 37 | static_assert(static_cast<int>(sizeof(kMatcherIndices) / sizeof(kMatcherIndices[0])) < |
| 38 | static_cast<int>(std::numeric_limits<MatcherIndex>::max() - 1), |
| 39 | "MatcherIndex is not large enough to index kMatcherIndices"); |
| 40 | |
| 41 | constexpr ParameterInfo kParameters[] = { |
| 42 | {{- range $i, $p := .Parameters }} |
| 43 | { |
| 44 | /* [{{$i}}] */ |
| 45 | /* usage */ ParameterUsage:: |
| 46 | {{- if $p.Usage }}k{{PascalCase $p.Usage}} |
| 47 | {{- else }}kNone |
| 48 | {{- end }}, |
| 49 | /* matcher indices */ &kMatcherIndices[{{$p.MatcherIndicesOffset}}], |
| 50 | }, |
| 51 | {{- end }} |
| 52 | }; |
| 53 | |
| 54 | constexpr OpenTypeInfo kOpenTypes[] = { |
| 55 | {{- range $i, $o := .OpenTypes }} |
| 56 | { |
| 57 | /* [{{$i}}] */ |
| 58 | /* name */ "{{$o.Name}}", |
| 59 | /* matcher index */ |
| 60 | {{- if ge $o.MatcherIndex 0 }} {{$o.MatcherIndex}} |
| 61 | {{- else }} kNoMatcher |
| 62 | {{- end }}, |
| 63 | }, |
| 64 | {{- end }} |
| 65 | }; |
| 66 | |
| 67 | constexpr OpenNumberInfo kOpenNumbers[] = { |
| 68 | {{- range $i, $o := .OpenNumbers }} |
| 69 | { |
| 70 | /* [{{$i}}] */ |
| 71 | /* name */ "{{$o.Name}}", |
| 72 | /* matcher index */ |
| 73 | {{- if ge $o.MatcherIndex 0 }} {{$o.MatcherIndex}} |
| 74 | {{- else }} kNoMatcher |
| 75 | {{- end }}, |
| 76 | }, |
| 77 | {{- end }} |
| 78 | }; |
| 79 | |
| 80 | constexpr OverloadInfo kOverloads[] = { |
| 81 | {{- range $i, $o := .Overloads }} |
| 82 | { |
| 83 | /* [{{$i}}] */ |
| 84 | /* num parameters */ {{$o.NumParameters}}, |
| 85 | /* num open types */ {{$o.NumOpenTypes}}, |
| 86 | /* num open numbers */ {{$o.NumOpenNumbers}}, |
| 87 | /* open types */ |
| 88 | {{- if $o.OpenTypesOffset }} &kOpenTypes[{{$o.OpenTypesOffset}}], |
| 89 | {{- else }} nullptr, |
| 90 | {{- end }} |
| 91 | /* open numbers */ |
| 92 | {{- if $o.OpenNumbersOffset }} &kOpenNumbers[{{$o.OpenNumbersOffset}}] |
| 93 | {{- else }} nullptr |
| 94 | {{- end }}, |
| 95 | /* parameters */ &kParameters[{{$o.ParametersOffset}}], |
| 96 | /* return matcher indices */ |
| 97 | {{- if $o.ReturnMatcherIndicesOffset }} &kMatcherIndices[{{$o.ReturnMatcherIndicesOffset}}] |
| 98 | {{- else }} nullptr |
| 99 | {{- end }}, |
| 100 | /* supported_stages */ PipelineStageSet( |
| 101 | {{- range $i, $u := $o.CanBeUsedInStage.List -}} |
| 102 | {{- if $i -}}, {{end}}PipelineStage::k{{Title $u}} |
| 103 | {{- end }}), |
| 104 | /* is_deprecated */ {{$o.IsDeprecated}}, |
| 105 | }, |
| 106 | {{- end }} |
| 107 | }; |
| 108 | |
Ben Clayton | e6e96de | 2022-05-09 18:08:23 +0000 | [diff] [blame] | 109 | constexpr IntrinsicInfo kBuiltins[] = { |
| 110 | {{- range $i, $b := .Builtins }} |
Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 111 | { |
| 112 | /* [{{$i}}] */ |
Ben Clayton | e6e96de | 2022-05-09 18:08:23 +0000 | [diff] [blame] | 113 | {{- range $b.OverloadDescriptions }} |
Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 114 | /* {{.}} */ |
| 115 | {{- end }} |
Ben Clayton | e6e96de | 2022-05-09 18:08:23 +0000 | [diff] [blame] | 116 | /* num overloads */ {{$b.NumOverloads}}, |
| 117 | /* overloads */ &kOverloads[{{$b.OverloadsOffset}}], |
Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 118 | }, |
| 119 | {{- end }} |
| 120 | }; |
| 121 | |
Ben Clayton | 77473b4 | 2022-05-13 14:35:37 +0000 | [diff] [blame^] | 122 | constexpr IntrinsicInfo kUnaryOperators[] = { |
| 123 | {{- range $i, $o := .UnaryOperators }} |
Ben Clayton | 9fb29a3 | 2022-05-09 20:00:13 +0000 | [diff] [blame] | 124 | { |
| 125 | /* [{{$i}}] */ |
| 126 | {{- range $o.OverloadDescriptions }} |
| 127 | /* {{.}} */ |
| 128 | {{- end }} |
| 129 | /* num overloads */ {{$o.NumOverloads}}, |
| 130 | /* overloads */ &kOverloads[{{$o.OverloadsOffset}}], |
| 131 | }, |
| 132 | {{- end }} |
| 133 | }; |
| 134 | |
Ben Clayton | 77473b4 | 2022-05-13 14:35:37 +0000 | [diff] [blame^] | 135 | {{- range $i, $o := .UnaryOperators }} |
| 136 | constexpr uint8_t kUnaryOperator{{template "OperatorName" $o.Name}} = {{$i}}; |
| 137 | {{- end }} |
| 138 | |
| 139 | constexpr IntrinsicInfo kBinaryOperators[] = { |
| 140 | {{- range $i, $o := .BinaryOperators }} |
| 141 | { |
| 142 | /* [{{$i}}] */ |
| 143 | {{- range $o.OverloadDescriptions }} |
| 144 | /* {{.}} */ |
| 145 | {{- end }} |
| 146 | /* num overloads */ {{$o.NumOverloads}}, |
| 147 | /* overloads */ &kOverloads[{{$o.OverloadsOffset}}], |
| 148 | }, |
| 149 | {{- end }} |
| 150 | }; |
| 151 | |
| 152 | {{- range $i, $o := .BinaryOperators }} |
| 153 | constexpr uint8_t kBinaryOperator{{template "OperatorName" $o.Name}} = {{$i}}; |
Ben Clayton | 9fb29a3 | 2022-05-09 20:00:13 +0000 | [diff] [blame] | 154 | {{- end }} |
| 155 | |
Ben Clayton | b85e692 | 2022-02-02 23:07:11 +0000 | [diff] [blame] | 156 | // clang-format on |
| 157 | {{ end -}} |
| 158 | |
| 159 | {{- /* ------------------------------------------------------------------ */ -}} |
| 160 | {{- define "Type" -}} |
| 161 | {{- /* ------------------------------------------------------------------ */ -}} |
| 162 | {{- $class := PascalCase .Name -}} |
| 163 | /// TypeMatcher for 'type {{.Name}}' |
| 164 | {{- if .Decl.Source.S.Filepath }} |
| 165 | /// @see {{.Decl.Source}} |
| 166 | {{- end }} |
| 167 | class {{$class}} : public TypeMatcher { |
| 168 | public: |
| 169 | /// Checks whether the given type matches the matcher rules. |
| 170 | /// Match may close open types and numbers in state. |
| 171 | /// @param state the MatchState |
| 172 | /// @param type the type to match |
| 173 | /// @returns the canonicalized type on match, otherwise nullptr |
| 174 | const sem::Type* Match(MatchState& state, |
| 175 | const sem::Type* type) const override; |
| 176 | /// @param state the MatchState |
| 177 | /// @return a string representation of the matcher. |
| 178 | std::string String(MatchState& state) const override; |
| 179 | }; |
| 180 | |
| 181 | const sem::Type* {{$class}}::Match(MatchState& state, const sem::Type* ty) const { |
| 182 | {{- range .TemplateParams }} |
| 183 | {{- template "DeclareLocalTemplateParam" . }} |
| 184 | {{- end }} |
| 185 | if (!match_{{TrimLeft .Name "_"}}(ty{{range .TemplateParams}}, {{.GetName}}{{end}})) { |
| 186 | return nullptr; |
| 187 | } |
| 188 | {{- range .TemplateParams }} |
| 189 | {{.Name}} = {{ template "MatchTemplateParam" .}}({{.Name}}); |
| 190 | if ({{ template "IsTemplateParamInvalid" .}}) { |
| 191 | return nullptr; |
| 192 | } |
| 193 | {{- end }} |
| 194 | return build_{{TrimLeft .Name "_"}}(state{{range .TemplateParams}}, {{.GetName}}{{end}}); |
| 195 | } |
| 196 | |
| 197 | std::string {{$class}}::String(MatchState&{{if .TemplateParams}} state{{end}}) const { |
| 198 | {{- range .TemplateParams }} |
| 199 | {{- template "DeclareLocalTemplateParamName" . }} |
| 200 | {{- end }} |
| 201 | |
| 202 | {{- if .DisplayName }} |
| 203 | std::stringstream ss; |
| 204 | ss{{range SplitDisplayName .DisplayName}} << {{.}}{{end}}; |
| 205 | return ss.str(); |
| 206 | {{- else if .TemplateParams }} |
| 207 | return "{{.Name}}<"{{template "AppendTemplateParamNames" .TemplateParams}} + ">"; |
| 208 | {{- else }} |
| 209 | return "{{.Name}}"; |
| 210 | {{- end }} |
| 211 | } |
| 212 | {{ end -}} |
| 213 | |
| 214 | {{- /* ------------------------------------------------------------------ */ -}} |
| 215 | {{- define "TypeMatcher" -}} |
| 216 | {{- /* ------------------------------------------------------------------ */ -}} |
| 217 | {{- $class := PascalCase .Name -}} |
| 218 | /// TypeMatcher for 'match {{.Name}}' |
| 219 | {{- if .Decl.Source.S.Filepath }} |
| 220 | /// @see {{.Decl.Source}} |
| 221 | {{- end }} |
| 222 | class {{$class}} : public TypeMatcher { |
| 223 | public: |
| 224 | /// Checks whether the given type matches the matcher rules, and returns the |
| 225 | /// expected, canonicalized type on success. |
| 226 | /// Match may close open types and numbers in state. |
| 227 | /// @param state the MatchState |
| 228 | /// @param type the type to match |
| 229 | /// @returns the canonicalized type on match, otherwise nullptr |
| 230 | const sem::Type* Match(MatchState& state, |
| 231 | const sem::Type* type) const override; |
| 232 | /// @param state the MatchState |
| 233 | /// @return a string representation of the matcher. |
| 234 | std::string String(MatchState& state) const override; |
| 235 | }; |
| 236 | |
| 237 | const sem::Type* {{$class}}::Match(MatchState& state, const sem::Type* ty) const { |
| 238 | {{- range .Types }} |
| 239 | if (match_{{.Name}}(ty)) { |
| 240 | return build_{{.Name}}(state); |
| 241 | } |
| 242 | {{- end }} |
| 243 | return nullptr; |
| 244 | } |
| 245 | |
| 246 | std::string {{$class}}::String(MatchState&) const { |
| 247 | return " |
| 248 | {{- range .Types -}} |
| 249 | {{- if IsFirstIn . $.Types }}{{.Name}} |
| 250 | {{- else if IsLastIn . $.Types }} or {{.Name}} |
| 251 | {{- else }}, {{.Name}} |
| 252 | {{- end -}} |
| 253 | {{- end -}} |
| 254 | "; |
| 255 | } |
| 256 | {{ end -}} |
| 257 | |
| 258 | {{- /* ------------------------------------------------------------------ */ -}} |
| 259 | {{- define "EnumMatcher" -}} |
| 260 | {{- /* ------------------------------------------------------------------ */ -}} |
| 261 | {{- $class := PascalCase .Name -}} |
| 262 | {{- $enum := PascalCase .Enum.Name -}} |
| 263 | /// EnumMatcher for 'match {{.Name}}' |
| 264 | {{- if .Decl.Source.S.Filepath }} |
| 265 | /// @see {{.Decl.Source}} |
| 266 | {{- end }} |
| 267 | class {{$class}} : public NumberMatcher { |
| 268 | public: |
| 269 | /// Checks whether the given number matches the enum matcher rules. |
| 270 | /// Match may close open types and numbers in state. |
| 271 | /// @param state the MatchState |
| 272 | /// @param number the enum value as a Number |
| 273 | /// @return true if the enum value matches the set |
| 274 | Number Match(MatchState& state, Number number) const override; |
| 275 | /// @param state the MatchState |
| 276 | /// @return a string representation of the matcher. |
| 277 | std::string String(MatchState& state) const override; |
| 278 | }; |
| 279 | |
| 280 | {{ if eq 1 (len .Options) -}} |
| 281 | {{- $option := index .Options 0 }} |
| 282 | {{- $entry := printf "k%v" (PascalCase $option.Name) -}} |
| 283 | Number {{$class}}::Match(MatchState&, Number number) const { |
| 284 | if (number.IsAny() || number.Value() == static_cast<uint32_t>({{$enum}}::{{$entry}})) { |
| 285 | return Number(static_cast<uint32_t>({{$enum}}::{{$entry}})); |
| 286 | } |
| 287 | return Number::invalid; |
| 288 | } |
| 289 | {{- else -}} |
| 290 | Number {{$class}}::Match(MatchState&, Number number) const { |
| 291 | switch (static_cast<{{$enum}}>(number.Value())) { |
| 292 | {{- range .Options }} |
| 293 | case {{$enum}}::k{{PascalCase .Name}}: |
| 294 | {{- end }} |
| 295 | return number; |
| 296 | default: |
| 297 | return Number::invalid; |
| 298 | } |
| 299 | } |
| 300 | {{- end }} |
| 301 | |
| 302 | std::string {{$class}}::String(MatchState&) const { |
| 303 | return " |
| 304 | {{- range .Options -}} |
| 305 | {{- if IsFirstIn . $.Options }}{{.Name}} |
| 306 | {{- else if IsLastIn . $.Options }} or {{.Name}} |
| 307 | {{- else }}, {{.Name}} |
| 308 | {{- end -}} |
| 309 | {{- end -}} |
| 310 | "; |
| 311 | } |
| 312 | {{ end -}} |
| 313 | |
| 314 | {{- /* ------------------------------------------------------------------ */ -}} |
| 315 | {{- define "Matchers" -}} |
| 316 | {{- /* ------------------------------------------------------------------ */ -}} |
| 317 | /// Matchers holds type and number matchers |
| 318 | class Matchers { |
| 319 | private: |
| 320 | {{- $t_names := Map -}} |
| 321 | {{- $n_names := Map -}} |
| 322 | {{- range Iterate .Sem.MaxOpenTypes -}} |
| 323 | {{- $name := printf "open_type_%v" . -}} |
| 324 | {{- $t_names.Put . $name }} |
| 325 | OpenTypeMatcher {{$name}}_{ {{- . -}} }; |
| 326 | {{- end }} |
| 327 | {{- range Iterate .Sem.MaxOpenNumbers -}} |
| 328 | {{- $name := printf "open_number_%v" . -}} |
| 329 | {{- $n_names.Put . $name }} |
| 330 | OpenNumberMatcher {{$name}}_{ {{- . -}} }; |
| 331 | {{- end }} |
| 332 | {{- range .Sem.Types -}} |
| 333 | {{- $name := PascalCase .Name -}} |
| 334 | {{- $t_names.Put . $name }} |
| 335 | {{$name}} {{$name}}_; |
| 336 | {{- end }} |
| 337 | {{- range .Sem.TypeMatchers -}} |
| 338 | {{- $name := PascalCase .Name -}} |
| 339 | {{- $t_names.Put . $name }} |
| 340 | {{$name}} {{$name}}_; |
| 341 | {{- end }} |
| 342 | {{- range .Sem.EnumMatchers -}} |
| 343 | {{- $name := PascalCase .Name -}} |
| 344 | {{- $n_names.Put . $name }} |
| 345 | {{$name}} {{$name}}_; |
| 346 | {{- end }} |
| 347 | |
| 348 | public: |
| 349 | /// Constructor |
| 350 | Matchers(); |
| 351 | /// Destructor |
| 352 | ~Matchers(); |
| 353 | |
| 354 | /// The open-types, types, and type matchers |
| 355 | TypeMatcher const* const type[{{len .TMatchers}}] = { |
| 356 | {{- range $i, $m := .TMatchers }} |
| 357 | /* [{{$i}}] */ |
| 358 | {{- if $m }} &{{$t_names.Get $m}}_, |
| 359 | {{- else }} &{{$t_names.Get $i}}_, |
| 360 | {{- end }} |
| 361 | {{- end }} |
| 362 | }; |
| 363 | |
| 364 | /// The open-numbers, and number matchers |
| 365 | NumberMatcher const* const number[{{len .NMatchers}}] = { |
| 366 | {{- range $i, $m := .NMatchers }} |
| 367 | /* [{{$i}}] */ |
| 368 | {{- if $m }} &{{$n_names.Get $m}}_, |
| 369 | {{- else }} &{{$n_names.Get $i}}_, |
| 370 | {{- end }} |
| 371 | {{- end }} |
| 372 | }; |
| 373 | }; |
| 374 | |
| 375 | Matchers::Matchers() = default; |
| 376 | Matchers::~Matchers() = default; |
| 377 | {{- end -}} |
| 378 | |
| 379 | {{- /* ------------------------------------------------------------------ */ -}} |
| 380 | {{- define "DeclareLocalTemplateParam" -}} |
| 381 | {{- /* ------------------------------------------------------------------ */ -}} |
| 382 | {{- if IsTemplateTypeParam . }} |
| 383 | const sem::Type* {{.Name}} = nullptr; |
| 384 | {{- else if IsTemplateNumberParam . }} |
| 385 | Number {{.Name}} = Number::invalid; |
| 386 | {{- else if IsTemplateEnumParam . }} |
| 387 | Number {{.Name}} = Number::invalid; |
| 388 | {{- end -}} |
| 389 | {{- end -}} |
| 390 | |
| 391 | {{- /* ------------------------------------------------------------------ */ -}} |
| 392 | {{- define "DeclareLocalTemplateParamName" -}} |
| 393 | {{- /* ------------------------------------------------------------------ */ -}} |
| 394 | {{- if IsTemplateTypeParam . }} |
| 395 | const std::string {{.Name}} = state.TypeName(); |
| 396 | {{- else if IsTemplateNumberParam . }} |
| 397 | const std::string {{.Name}} = state.NumName(); |
| 398 | {{- else if IsTemplateEnumParam . }} |
| 399 | const std::string {{.Name}} = state.NumName(); |
| 400 | {{- end -}} |
| 401 | {{- end -}} |
| 402 | |
| 403 | {{- /* ------------------------------------------------------------------ */ -}} |
| 404 | {{- define "MatchTemplateParam" -}} |
| 405 | {{- /* ------------------------------------------------------------------ */ -}} |
| 406 | {{- if IsTemplateTypeParam . -}} |
| 407 | state.Type |
| 408 | {{- else if IsTemplateNumberParam . -}} |
| 409 | state.Num |
| 410 | {{- else if IsTemplateEnumParam . -}} |
| 411 | state.Num |
| 412 | {{- end -}} |
| 413 | {{- end -}} |
| 414 | |
| 415 | {{- /* ------------------------------------------------------------------ */ -}} |
| 416 | {{- define "IsTemplateParamInvalid" -}} |
| 417 | {{- /* ------------------------------------------------------------------ */ -}} |
| 418 | {{- if IsTemplateTypeParam . -}} |
| 419 | {{.Name}} == nullptr |
| 420 | {{- else if IsTemplateNumberParam . -}} |
| 421 | !{{.Name}}.IsValid() |
| 422 | {{- else if IsTemplateEnumParam . -}} |
| 423 | !{{.Name}}.IsValid() |
| 424 | {{- end -}} |
| 425 | {{- end -}} |
| 426 | |
| 427 | {{- /* ------------------------------------------------------------------ */ -}} |
| 428 | {{- define "AppendTemplateParamNames" -}} |
| 429 | {{- /* ------------------------------------------------------------------ */ -}} |
| 430 | {{- range $i, $ := . -}} |
| 431 | {{- if $i }} + ", " + {{.Name}} |
| 432 | {{- else }} + {{.Name}} |
| 433 | {{- end -}} |
| 434 | {{- end -}} |
| 435 | {{- end -}} |
Ben Clayton | 9fb29a3 | 2022-05-09 20:00:13 +0000 | [diff] [blame] | 436 | |
| 437 | {{- /* ------------------------------------------------------------------ */ -}} |
| 438 | {{- define "OperatorName" -}} |
| 439 | {{- /* ------------------------------------------------------------------ */ -}} |
| 440 | {{- if eq . "<<" -}}ShiftLeft |
| 441 | {{- else if eq . "&" -}}And |
| 442 | {{- else if eq . "|" -}}Or |
| 443 | {{- else if eq . "^" -}}Xor |
| 444 | {{- else if eq . "&&" -}}LogicalAnd |
| 445 | {{- else if eq . "||" -}}LogicalOr |
| 446 | {{- else if eq . "==" -}}Equal |
Ben Clayton | b61e045 | 2022-05-09 21:22:24 +0000 | [diff] [blame] | 447 | {{- else if eq . "!" -}}Not |
Ben Clayton | 9fb29a3 | 2022-05-09 20:00:13 +0000 | [diff] [blame] | 448 | {{- else if eq . "!=" -}}NotEqual |
Ben Clayton | b61e045 | 2022-05-09 21:22:24 +0000 | [diff] [blame] | 449 | {{- else if eq . "~" -}}Complement |
Ben Clayton | 9fb29a3 | 2022-05-09 20:00:13 +0000 | [diff] [blame] | 450 | {{- else if eq . "<" -}}LessThan |
| 451 | {{- else if eq . ">" -}}GreaterThan |
| 452 | {{- else if eq . "<=" -}}LessThanEqual |
| 453 | {{- else if eq . ">=" -}}GreaterThanEqual |
| 454 | {{- else if eq . "<<" -}}ShiftLeft |
| 455 | {{- else if eq . ">>" -}}ShiftRight |
| 456 | {{- else if eq . "+" -}}Plus |
| 457 | {{- else if eq . "-" -}}Minus |
| 458 | {{- else if eq . "*" -}}Star |
| 459 | {{- else if eq . "/" -}}Divide |
| 460 | {{- else if eq . "%" -}}Modulo |
| 461 | {{- else -}}<unknown-{{.}}> |
| 462 | {{- end -}} |
| 463 | {{- end -}} |