From e6e96def663ec4370c0682c444928d0c97f5d389 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 9 May 2022 18:08:23 +0000 Subject: [PATCH] tint: Add operator support to intrinsic-gen Adapt the builtin parsing and resolving to also support operators. Will be used to generate intrinsic table entries for operators. This will simplify maintenance of the operators, and will greatly simplify the [AbstractInt -> i32|u32] [AbstractFloat -> f32|f16] logic. Bug: tint:1504 Change-Id: Id75735ea24e501877418812185796f3fba88a521 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/89026 Commit-Queue: Ben Clayton Kokoro: Kokoro Reviewed-by: Dan Sinclair --- src/tint/resolver/intrinsic_table.cc | 29 +- src/tint/resolver/intrinsic_table.inl | 98 ++-- src/tint/resolver/intrinsic_table.inl.tmpl | 12 +- src/tint/sem/builtin_type.cc.tmpl | 4 +- src/tint/sem/builtin_type.h.tmpl | 2 +- test/tint/builtins/builtins.wgsl.tmpl | 12 +- tools/src/cmd/intrinsic-gen/ast/ast.go | 42 +- .../cmd/intrinsic-gen/gen/builtin_table.go | 98 ++-- tools/src/cmd/intrinsic-gen/gen/generate.go | 16 +- tools/src/cmd/intrinsic-gen/gen/permutate.go | 2 +- tools/src/cmd/intrinsic-gen/lexer/lexer.go | 32 +- .../src/cmd/intrinsic-gen/lexer/lexer_test.go | 53 +- tools/src/cmd/intrinsic-gen/parser/parser.go | 55 +- .../cmd/intrinsic-gen/parser/parser_test.go | 509 +++++++++++++----- .../src/cmd/intrinsic-gen/resolver/resolve.go | 59 +- .../intrinsic-gen/resolver/resolver_test.go | 66 ++- tools/src/cmd/intrinsic-gen/sem/sem.go | 24 +- tools/src/cmd/intrinsic-gen/tok/tok.go | 17 + 18 files changed, 783 insertions(+), 347 deletions(-) diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index 7656e55429..58cc0b0dd0 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -762,9 +762,9 @@ struct OverloadInfo { bool is_deprecated; }; -/// BuiltinInfo describes a builtin function -struct BuiltinInfo { - /// Number of overloads of the builtin function +/// IntrinsicInfo describes a builtin function +struct IntrinsicInfo { + /// Number of overloads of the intrinsic const uint8_t num_overloads; /// Pointer to the start of the overloads for the function OverloadInfo const* const overloads; @@ -772,9 +772,8 @@ struct BuiltinInfo { #include "intrinsic_table.inl" -/// BuiltinPrototype describes a fully matched builtin function, which is -/// used as a lookup for building unique sem::Builtin instances. -struct BuiltinPrototype { +/// IntrinsicPrototype describes a fully matched intrinsic. +struct IntrinsicPrototype { /// Parameter describes a single parameter struct Parameter { /// Parameter type @@ -783,11 +782,11 @@ struct BuiltinPrototype { ParameterUsage const usage = ParameterUsage::kNone; }; - /// Hasher provides a hash function for the BuiltinPrototype + /// Hasher provides a hash function for the IntrinsicPrototype struct Hasher { - /// @param i the BuiltinPrototype to create a hash for + /// @param i the IntrinsicPrototype to create a hash for /// @return the hash value - inline std::size_t operator()(const BuiltinPrototype& i) const { + inline std::size_t operator()(const IntrinsicPrototype& i) const { size_t hash = utils::Hash(i.parameters.size()); for (auto& p : i.parameters) { utils::HashCombine(&hash, p.type, p.usage); @@ -803,8 +802,8 @@ struct BuiltinPrototype { bool is_deprecated = false; }; -/// Equality operator for BuiltinPrototype -bool operator==(const BuiltinPrototype& a, const BuiltinPrototype& b) { +/// Equality operator for IntrinsicPrototype +bool operator==(const IntrinsicPrototype& a, const IntrinsicPrototype& b) { if (a.type != b.type || a.supported_stages != b.supported_stages || a.return_type != b.return_type || a.is_deprecated != b.is_deprecated || a.parameters.size() != b.parameters.size()) { @@ -845,7 +844,7 @@ class Impl : public IntrinsicTable { ProgramBuilder& builder; Matchers matchers; - std::unordered_map builtins; + std::unordered_map builtins; }; /// @return a string representing a call to a builtin with the given argument @@ -949,7 +948,7 @@ const sem::Builtin* Impl::Match(sem::BuiltinType builtin_type, ClosedState closed(builder); - std::vector parameters; + std::vector parameters; auto num_params = std::min(num_parameters, num_arguments); for (uint32_t p = 0; p < num_params; p++) { @@ -957,7 +956,7 @@ const sem::Builtin* Impl::Match(sem::BuiltinType builtin_type, auto* indices = parameter.matcher_indices; auto* type = Match(closed, overload, indices).Type(args[p]->UnwrapRef()); if (type) { - parameters.emplace_back(BuiltinPrototype::Parameter{type, parameter.usage}); + parameters.emplace_back(IntrinsicPrototype::Parameter{type, parameter.usage}); match_score += kScorePerMatchedParam; } else { overload_matched = false; @@ -1014,7 +1013,7 @@ const sem::Builtin* Impl::Match(sem::BuiltinType builtin_type, return_type = builder.create(); } - BuiltinPrototype builtin; + IntrinsicPrototype builtin; builtin.type = builtin_type; builtin.return_type = return_type; builtin.parameters = std::move(parameters); diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl index fa48359728..acced8f4ef 100644 --- a/src/tint/resolver/intrinsic_table.inl +++ b/src/tint/resolver/intrinsic_table.inl @@ -13,11 +13,11 @@ // limitations under the License. //////////////////////////////////////////////////////////////////////////////// -// File generated by tools/builtin-gen +// File generated by tools/intrinsic-gen // using the template: -// src/tint/builtin_table.inl.tmpl -// and the builtin defintion file: -// src/tint/builtins.def +// src/tint/resolver/intrinsic_table.inl.tmpl +// and the intrinsic defintion file: +// src/tint/intrinsics.def // // Do not modify this file directly //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +25,7 @@ // clang-format off /// TypeMatcher for 'type bool' -/// @see src/tint/builtins.def:68:6 +/// @see src/tint/intrinsics.def:68:6 class Bool : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -52,7 +52,7 @@ std::string Bool::String(MatchState&) const { } /// TypeMatcher for 'type f32' -/// @see src/tint/builtins.def:69:6 +/// @see src/tint/intrinsics.def:69:6 class F32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -79,7 +79,7 @@ std::string F32::String(MatchState&) const { } /// TypeMatcher for 'type i32' -/// @see src/tint/builtins.def:70:6 +/// @see src/tint/intrinsics.def:70:6 class I32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -106,7 +106,7 @@ std::string I32::String(MatchState&) const { } /// TypeMatcher for 'type u32' -/// @see src/tint/builtins.def:71:6 +/// @see src/tint/intrinsics.def:71:6 class U32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -133,7 +133,7 @@ std::string U32::String(MatchState&) const { } /// TypeMatcher for 'type vec2' -/// @see src/tint/builtins.def:72:6 +/// @see src/tint/intrinsics.def:72:6 class Vec2 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -166,7 +166,7 @@ std::string Vec2::String(MatchState& state) const { } /// TypeMatcher for 'type vec3' -/// @see src/tint/builtins.def:73:6 +/// @see src/tint/intrinsics.def:73:6 class Vec3 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -199,7 +199,7 @@ std::string Vec3::String(MatchState& state) const { } /// TypeMatcher for 'type vec4' -/// @see src/tint/builtins.def:74:6 +/// @see src/tint/intrinsics.def:74:6 class Vec4 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -232,7 +232,7 @@ std::string Vec4::String(MatchState& state) const { } /// TypeMatcher for 'type vec' -/// @see src/tint/builtins.def:75:37 +/// @see src/tint/intrinsics.def:75:37 class Vec : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -273,7 +273,7 @@ std::string Vec::String(MatchState& state) const { } /// TypeMatcher for 'type mat' -/// @see src/tint/builtins.def:76:37 +/// @see src/tint/intrinsics.def:76:37 class Mat : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -320,7 +320,7 @@ std::string Mat::String(MatchState& state) const { } /// TypeMatcher for 'type ptr' -/// @see src/tint/builtins.def:77:6 +/// @see src/tint/intrinsics.def:77:6 class Ptr : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -365,7 +365,7 @@ std::string Ptr::String(MatchState& state) const { } /// TypeMatcher for 'type atomic' -/// @see src/tint/builtins.def:78:6 +/// @see src/tint/intrinsics.def:78:6 class Atomic : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -398,7 +398,7 @@ std::string Atomic::String(MatchState& state) const { } /// TypeMatcher for 'type array' -/// @see src/tint/builtins.def:79:6 +/// @see src/tint/intrinsics.def:79:6 class Array : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -431,7 +431,7 @@ std::string Array::String(MatchState& state) const { } /// TypeMatcher for 'type sampler' -/// @see src/tint/builtins.def:80:6 +/// @see src/tint/intrinsics.def:80:6 class Sampler : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -458,7 +458,7 @@ std::string Sampler::String(MatchState&) const { } /// TypeMatcher for 'type sampler_comparison' -/// @see src/tint/builtins.def:81:6 +/// @see src/tint/intrinsics.def:81:6 class SamplerComparison : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -485,7 +485,7 @@ std::string SamplerComparison::String(MatchState&) const { } /// TypeMatcher for 'type texture_1d' -/// @see src/tint/builtins.def:82:6 +/// @see src/tint/intrinsics.def:82:6 class Texture1D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -518,7 +518,7 @@ std::string Texture1D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_2d' -/// @see src/tint/builtins.def:83:6 +/// @see src/tint/intrinsics.def:83:6 class Texture2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -551,7 +551,7 @@ std::string Texture2D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_2d_array' -/// @see src/tint/builtins.def:84:6 +/// @see src/tint/intrinsics.def:84:6 class Texture2DArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -584,7 +584,7 @@ std::string Texture2DArray::String(MatchState& state) const { } /// TypeMatcher for 'type texture_3d' -/// @see src/tint/builtins.def:85:6 +/// @see src/tint/intrinsics.def:85:6 class Texture3D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -617,7 +617,7 @@ std::string Texture3D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_cube' -/// @see src/tint/builtins.def:86:6 +/// @see src/tint/intrinsics.def:86:6 class TextureCube : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -650,7 +650,7 @@ std::string TextureCube::String(MatchState& state) const { } /// TypeMatcher for 'type texture_cube_array' -/// @see src/tint/builtins.def:87:6 +/// @see src/tint/intrinsics.def:87:6 class TextureCubeArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -683,7 +683,7 @@ std::string TextureCubeArray::String(MatchState& state) const { } /// TypeMatcher for 'type texture_multisampled_2d' -/// @see src/tint/builtins.def:88:6 +/// @see src/tint/intrinsics.def:88:6 class TextureMultisampled2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -716,7 +716,7 @@ std::string TextureMultisampled2D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_depth_2d' -/// @see src/tint/builtins.def:89:6 +/// @see src/tint/intrinsics.def:89:6 class TextureDepth2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -743,7 +743,7 @@ std::string TextureDepth2D::String(MatchState&) const { } /// TypeMatcher for 'type texture_depth_2d_array' -/// @see src/tint/builtins.def:90:6 +/// @see src/tint/intrinsics.def:90:6 class TextureDepth2DArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -770,7 +770,7 @@ std::string TextureDepth2DArray::String(MatchState&) const { } /// TypeMatcher for 'type texture_depth_cube' -/// @see src/tint/builtins.def:91:6 +/// @see src/tint/intrinsics.def:91:6 class TextureDepthCube : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -797,7 +797,7 @@ std::string TextureDepthCube::String(MatchState&) const { } /// TypeMatcher for 'type texture_depth_cube_array' -/// @see src/tint/builtins.def:92:6 +/// @see src/tint/intrinsics.def:92:6 class TextureDepthCubeArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -824,7 +824,7 @@ std::string TextureDepthCubeArray::String(MatchState&) const { } /// TypeMatcher for 'type texture_depth_multisampled_2d' -/// @see src/tint/builtins.def:93:6 +/// @see src/tint/intrinsics.def:93:6 class TextureDepthMultisampled2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -851,7 +851,7 @@ std::string TextureDepthMultisampled2D::String(MatchState&) const { } /// TypeMatcher for 'type texture_storage_1d' -/// @see src/tint/builtins.def:94:6 +/// @see src/tint/intrinsics.def:94:6 class TextureStorage1D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -890,7 +890,7 @@ std::string TextureStorage1D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_storage_2d' -/// @see src/tint/builtins.def:95:6 +/// @see src/tint/intrinsics.def:95:6 class TextureStorage2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -929,7 +929,7 @@ std::string TextureStorage2D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_storage_2d_array' -/// @see src/tint/builtins.def:96:6 +/// @see src/tint/intrinsics.def:96:6 class TextureStorage2DArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -968,7 +968,7 @@ std::string TextureStorage2DArray::String(MatchState& state) const { } /// TypeMatcher for 'type texture_storage_3d' -/// @see src/tint/builtins.def:97:6 +/// @see src/tint/intrinsics.def:97:6 class TextureStorage3D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -1007,7 +1007,7 @@ std::string TextureStorage3D::String(MatchState& state) const { } /// TypeMatcher for 'type texture_external' -/// @see src/tint/builtins.def:98:6 +/// @see src/tint/intrinsics.def:98:6 class TextureExternal : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -1034,7 +1034,7 @@ std::string TextureExternal::String(MatchState&) const { } /// TypeMatcher for 'type __modf_result' -/// @see src/tint/builtins.def:100:6 +/// @see src/tint/intrinsics.def:100:6 class ModfResult : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -1061,7 +1061,7 @@ std::string ModfResult::String(MatchState&) const { } /// TypeMatcher for 'type __modf_result_vec' -/// @see src/tint/builtins.def:101:42 +/// @see src/tint/intrinsics.def:101:42 class ModfResultVec : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -1096,7 +1096,7 @@ std::string ModfResultVec::String(MatchState& state) const { } /// TypeMatcher for 'type __frexp_result' -/// @see src/tint/builtins.def:102:6 +/// @see src/tint/intrinsics.def:102:6 class FrexpResult : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -1123,7 +1123,7 @@ std::string FrexpResult::String(MatchState&) const { } /// TypeMatcher for 'type __frexp_result_vec' -/// @see src/tint/builtins.def:103:43 +/// @see src/tint/intrinsics.def:103:43 class FrexpResultVec : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. @@ -1158,7 +1158,7 @@ std::string FrexpResultVec::String(MatchState& state) const { } /// TypeMatcher for 'match fiu32' -/// @see src/tint/builtins.def:111:7 +/// @see src/tint/intrinsics.def:111:7 class Fiu32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the @@ -1192,7 +1192,7 @@ std::string Fiu32::String(MatchState&) const { } /// TypeMatcher for 'match iu32' -/// @see src/tint/builtins.def:112:7 +/// @see src/tint/intrinsics.def:112:7 class Iu32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the @@ -1223,7 +1223,7 @@ std::string Iu32::String(MatchState&) const { } /// TypeMatcher for 'match scalar' -/// @see src/tint/builtins.def:113:7 +/// @see src/tint/intrinsics.def:113:7 class Scalar : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the @@ -1260,7 +1260,7 @@ std::string Scalar::String(MatchState&) const { } /// EnumMatcher for 'match f32_texel_format' -/// @see src/tint/builtins.def:124:7 +/// @see src/tint/intrinsics.def:124:7 class F32TexelFormat : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. @@ -1293,7 +1293,7 @@ std::string F32TexelFormat::String(MatchState&) const { } /// EnumMatcher for 'match i32_texel_format' -/// @see src/tint/builtins.def:126:7 +/// @see src/tint/intrinsics.def:126:7 class I32TexelFormat : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. @@ -1325,7 +1325,7 @@ std::string I32TexelFormat::String(MatchState&) const { } /// EnumMatcher for 'match u32_texel_format' -/// @see src/tint/builtins.def:128:7 +/// @see src/tint/intrinsics.def:128:7 class U32TexelFormat : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. @@ -1357,7 +1357,7 @@ std::string U32TexelFormat::String(MatchState&) const { } /// EnumMatcher for 'match write_only' -/// @see src/tint/builtins.def:131:7 +/// @see src/tint/intrinsics.def:131:7 class WriteOnly : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. @@ -1383,7 +1383,7 @@ std::string WriteOnly::String(MatchState&) const { } /// EnumMatcher for 'match function_private_workgroup' -/// @see src/tint/builtins.def:133:7 +/// @see src/tint/intrinsics.def:133:7 class FunctionPrivateWorkgroup : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. @@ -1413,7 +1413,7 @@ std::string FunctionPrivateWorkgroup::String(MatchState&) const { } /// EnumMatcher for 'match workgroup_or_storage' -/// @see src/tint/builtins.def:134:7 +/// @see src/tint/intrinsics.def:134:7 class WorkgroupOrStorage : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. @@ -8814,7 +8814,7 @@ constexpr OverloadInfo kOverloads[] = { }, }; -constexpr BuiltinInfo kBuiltins[] = { +constexpr IntrinsicInfo kBuiltins[] = { { /* [0] */ /* fn abs(T) -> T */ diff --git a/src/tint/resolver/intrinsic_table.inl.tmpl b/src/tint/resolver/intrinsic_table.inl.tmpl index 931ae247ae..b39ad5dc86 100644 --- a/src/tint/resolver/intrinsic_table.inl.tmpl +++ b/src/tint/resolver/intrinsic_table.inl.tmpl @@ -23,7 +23,7 @@ See: {{ end -}} {{- end -}} -{{- with BuiltinTable -}} +{{- with IntrinsicTable -}} {{- template "Matchers" . }} constexpr MatcherIndex kMatcherIndices[] = { @@ -106,15 +106,15 @@ constexpr OverloadInfo kOverloads[] = { {{- end }} }; -constexpr BuiltinInfo kBuiltins[] = { -{{- range $i, $f := .Functions }} +constexpr IntrinsicInfo kBuiltins[] = { +{{- range $i, $b := .Builtins }} { /* [{{$i}}] */ -{{- range $f.OverloadDescriptions }} +{{- range $b.OverloadDescriptions }} /* {{.}} */ {{- end }} - /* num overloads */ {{$f.NumOverloads}}, - /* overloads */ &kOverloads[{{$f.OverloadsOffset}}], + /* num overloads */ {{$b.NumOverloads}}, + /* overloads */ &kOverloads[{{$b.OverloadsOffset}}], }, {{- end }} }; diff --git a/src/tint/sem/builtin_type.cc.tmpl b/src/tint/sem/builtin_type.cc.tmpl index 63c20830c6..4e830dac95 100644 --- a/src/tint/sem/builtin_type.cc.tmpl +++ b/src/tint/sem/builtin_type.cc.tmpl @@ -15,7 +15,7 @@ See: namespace tint::sem { BuiltinType ParseBuiltinType(const std::string& name) { -{{- range .Sem.Functions }} +{{- range .Sem.Builtins }} if (name == "{{.Name}}") { return BuiltinType::k{{Title .Name}}; } @@ -27,7 +27,7 @@ const char* str(BuiltinType i) { switch (i) { case BuiltinType::kNone: return ""; -{{- range .Sem.Functions }} +{{- range .Sem.Builtins }} case BuiltinType::k{{Title .Name}}: return "{{.Name}}"; {{- end }} diff --git a/src/tint/sem/builtin_type.h.tmpl b/src/tint/sem/builtin_type.h.tmpl index d4e1cc77d3..258ac87f72 100644 --- a/src/tint/sem/builtin_type.h.tmpl +++ b/src/tint/sem/builtin_type.h.tmpl @@ -19,7 +19,7 @@ namespace tint::sem { /// Enumerator of all builtin functions enum class BuiltinType { kNone = -1, -{{- range .Sem.Functions }} +{{- range .Sem.Builtins }} k{{Title .Name}}, {{- end }} }; diff --git a/test/tint/builtins/builtins.wgsl.tmpl b/test/tint/builtins/builtins.wgsl.tmpl index 0edd48ebd8..ecc76a5493 100644 --- a/test/tint/builtins/builtins.wgsl.tmpl +++ b/test/tint/builtins/builtins.wgsl.tmpl @@ -9,15 +9,15 @@ See: -------------------------------------------------------------------------------- */ -}} -{{- /* For each permutation of each overload of each function... */ -}} -{{- range .Sem.Functions -}} +{{- /* For each permutation of each overload of each builtin... */ -}} +{{- range .Sem.Builtins -}} {{- /* TODO(crbug.com/tint/1483): Remove the bodge below after smoothStep is removed from builtins.def */}} {{- if not (eq .Name "smoothStep") }} {{- range .Overloads -}} {{- range Permute . -}} {{- /* Generate a ./gen//.wgsl file using the Permutation macro defined below */ -}} -{{- $file := printf "./gen/%v/%v.wgsl" .Function.Name .Hash -}} +{{- $file := printf "./gen/%v/%v.wgsl" .Intrinsic.Name .Hash -}} {{- $content := Eval "Permutation" . -}} {{- WriteFile $file $content -}} {{- end }} @@ -30,8 +30,8 @@ See: {{- define "Permutation" -}} {{- /* Emits the body of the intrinsic permuation .wgsl file */ -}} {{- /* ------------------------------------------------------------------ */ -}} -{{- $function := .Function.Name -}} -{{- $permutation := printf "%v_%v" $function .Hash -}} +{{- $builtin := .Intrinsic.Name -}} +{{- $permutation := printf "%v_%v" $builtin .Hash -}} {{- $args := Map -}} {{- /* Generate RW storage buffer parameters */ -}} @@ -125,7 +125,7 @@ fn {{$permutation}}() { {{- if .ReturnType -}} var res{{if IsDeclarable .ReturnType}}: {{template "Type" .ReturnType}}{{end}} = {{/* preserve space after = */ -}} {{- end -}} - {{$function}}( + {{$builtin}}( {{- range $i, $p := .Parameters -}} {{- if $i -}}, {{end}}{{$args.Get $i -}} {{- end -}} diff --git a/tools/src/cmd/intrinsic-gen/ast/ast.go b/tools/src/cmd/intrinsic-gen/ast/ast.go index 92dcaa7800..17454a0dd8 100644 --- a/tools/src/cmd/intrinsic-gen/ast/ast.go +++ b/tools/src/cmd/intrinsic-gen/ast/ast.go @@ -28,7 +28,8 @@ type AST struct { Enums []EnumDecl Types []TypeDecl Matchers []MatcherDecl - Functions []FunctionDecl + Builtins []IntrinsicDecl + Operators []IntrinsicDecl } func (a AST) String() string { @@ -45,8 +46,12 @@ func (a AST) String() string { fmt.Fprintf(&sb, "%v", m) fmt.Fprintln(&sb) } - for _, f := range a.Functions { - fmt.Fprintf(&sb, "%v", f) + for _, b := range a.Builtins { + fmt.Fprintf(&sb, "%v", b) + fmt.Fprintln(&sb) + } + for _, o := range a.Operators { + fmt.Fprintf(&sb, "%v", o) fmt.Fprintln(&sb) } return sb.String() @@ -98,9 +103,18 @@ func (m MatcherDecl) Format(w fmt.State, verb rune) { m.Options.Format(w, verb) } -// FunctionDecl describes a function declaration -type FunctionDecl struct { +// IntrinsicKind is either a Builtin or Operator +type IntrinsicKind string + +const ( + Builtin IntrinsicKind = "builtin" + Operator IntrinsicKind = "operator" +) + +// IntrinsicDecl describes a builtin or operator declaration +type IntrinsicDecl struct { Source tok.Source + Kind IntrinsicKind Name string Decorations Decorations TemplateParams TemplateParams @@ -109,13 +123,19 @@ type FunctionDecl struct { } // Format implements the fmt.Formatter interface -func (f FunctionDecl) Format(w fmt.State, verb rune) { - fmt.Fprintf(w, "fn %v", f.Name) - f.TemplateParams.Format(w, verb) - f.Parameters.Format(w, verb) - if f.ReturnType != nil { +func (i IntrinsicDecl) Format(w fmt.State, verb rune) { + switch i.Kind { + case Builtin: + fmt.Fprintf(w, "fn ") + case Operator: + fmt.Fprintf(w, "op ") + } + fmt.Fprintf(w, "%v", i.Name) + i.TemplateParams.Format(w, verb) + i.Parameters.Format(w, verb) + if i.ReturnType != nil { fmt.Fprintf(w, " -> ") - f.ReturnType.Format(w, verb) + i.ReturnType.Format(w, verb) } } diff --git a/tools/src/cmd/intrinsic-gen/gen/builtin_table.go b/tools/src/cmd/intrinsic-gen/gen/builtin_table.go index b3bfa16743..94c8a5cd90 100644 --- a/tools/src/cmd/intrinsic-gen/gen/builtin_table.go +++ b/tools/src/cmd/intrinsic-gen/gen/builtin_table.go @@ -22,8 +22,8 @@ import ( "dawn.googlesource.com/dawn/tools/src/lut" ) -// BuiltinTable holds data specific to the intrinsic_table.inl.tmpl template -type BuiltinTable struct { +// IntrinsicTable holds data specific to the intrinsic_table.inl.tmpl template +type IntrinsicTable struct { // The semantic info Sem *sem.Sem @@ -42,7 +42,8 @@ type BuiltinTable struct { OpenNumbers []OpenNumber // kOpenNumbers table content Parameters []Parameter // kParameters table content Overloads []Overload // kOverloads table content - Functions []Function // kBuiltins table content + Builtins []Intrinsic // kBuiltins table content + Operators []Intrinsic // kOperators table content } // OpenType is used to create the C++ OpenTypeInfo structure @@ -68,9 +69,9 @@ type Parameter struct { // The parameter usage (parameter name) Usage string - // Index into BuiltinTable.MatcherIndices, beginning the list of matchers + // Index into IntrinsicTable.MatcherIndices, beginning the list of matchers // required to match the parameter type. The matcher indices index - // into BuiltinTable::TMatchers and / or BuiltinTable::NMatchers. + // into IntrinsicTable::TMatchers and / or IntrinsicTable::NMatchers. // These indices are consumed by the matchers themselves. // The first index is always a TypeMatcher. MatcherIndicesOffset *int @@ -84,15 +85,15 @@ type Overload struct { NumOpenTypes int // Total number of open numbers for the overload NumOpenNumbers int - // Index to the first open type in BuiltinTable.OpenTypes + // Index to the first open type in IntrinsicTable.OpenTypes OpenTypesOffset *int - // Index to the first open number in BuiltinTable.OpenNumbers + // Index to the first open number in IntrinsicTable.OpenNumbers OpenNumbersOffset *int - // Index to the first parameter in BuiltinTable.Parameters + // Index to the first parameter in IntrinsicTable.Parameters ParametersOffset *int - // Index into BuiltinTable.MatcherIndices, beginning the list of matchers + // Index into IntrinsicTable.MatcherIndices, beginning the list of matchers // required to match the return type. The matcher indices index - // into BuiltinTable::TMatchers and / or BuiltinTable::NMatchers. + // into IntrinsicTable::TMatchers and / or IntrinsicTable::NMatchers. // These indices are consumed by the matchers themselves. // The first index is always a TypeMatcher. ReturnMatcherIndicesOffset *int @@ -102,17 +103,18 @@ type Overload struct { IsDeprecated bool } -// Function is used to create the C++ IntrinsicInfo structure -type Function struct { +// Intrinsic is used to create the C++ IntrinsicInfo structure +type Intrinsic struct { + Name string OverloadDescriptions []string NumOverloads int OverloadsOffset *int } -// Helper for building the BuiltinTable -type BuiltinTableBuilder struct { +// Helper for building the IntrinsicTable +type IntrinsicTableBuilder struct { // The output of the builder - BuiltinTable + IntrinsicTable // Lookup tables. // These are packed (compressed) once all the entries have been added. @@ -127,7 +129,7 @@ type BuiltinTableBuilder struct { // Helper for building a single overload type overloadBuilder struct { - *BuiltinTableBuilder + *IntrinsicTableBuilder // Maps TemplateParam to index in openTypes openTypeIndex map[sem.TemplateParam]int // Maps TemplateParam to index in openNumbers @@ -138,9 +140,9 @@ type overloadBuilder struct { openNumbers []OpenNumber // All parameters declared by the overload parameters []Parameter - // Index into BuiltinTable.MatcherIndices, beginning the list of matchers + // Index into IntrinsicTable.MatcherIndices, beginning the list of matchers // required to match the return type. The matcher indices index - // into BuiltinTable::TMatchers and / or BuiltinTable::NMatchers. + // into IntrinsicTable::TMatchers and / or IntrinsicTable::NMatchers. // These indices are consumed by the matchers themselves. // The first index is always a TypeMatcher. returnTypeMatcherIndicesOffset *int @@ -148,7 +150,7 @@ type overloadBuilder struct { // layoutMatchers assigns each of the TMatchers and NMatchers a unique index // in the C++ Matchers::type and Matchers::number arrays, respectively. -func (b *BuiltinTableBuilder) layoutMatchers(s *sem.Sem) { +func (b *IntrinsicTableBuilder) layoutMatchers(s *sem.Sem) { // First MaxOpenTypes of TMatchers are open types b.TMatchers = make([]sem.Named, s.MaxOpenTypes) for _, m := range s.Types { @@ -169,11 +171,11 @@ func (b *BuiltinTableBuilder) layoutMatchers(s *sem.Sem) { } // buildOverload constructs an Overload for a sem.Overload -func (b *BuiltinTableBuilder) buildOverload(o *sem.Overload) (Overload, error) { +func (b *IntrinsicTableBuilder) buildOverload(o *sem.Overload) (Overload, error) { ob := overloadBuilder{ - BuiltinTableBuilder: b, - openTypeIndex: map[sem.TemplateParam]int{}, - openNumberIndex: map[sem.TemplateParam]int{}, + IntrinsicTableBuilder: b, + openTypeIndex: map[sem.TemplateParam]int{}, + openNumberIndex: map[sem.TemplateParam]int{}, } if err := ob.buildOpenTypes(o); err != nil { @@ -279,7 +281,7 @@ func (b *overloadBuilder) buildReturnType(o *sem.Overload) error { } // matcherIndex returns the index of TMatcher or NMatcher in -// BuiltinTable.TMatcher or BuiltinTable.NMatcher, respectively. +// IntrinsicTable.TMatcher or IntrinsicTable.NMatcher, respectively. func (b *overloadBuilder) matcherIndex(n sem.Named) (int, error) { switch n := n.(type) { case *sem.Type, *sem.TypeMatcher: @@ -342,10 +344,10 @@ func (b *overloadBuilder) collectMatcherIndices(fqn sem.FullyQualifiedName) ([]i return out, nil } -// buildBuiltinTable builds the BuiltinTable from the semantic info -func buildBuiltinTable(s *sem.Sem) (*BuiltinTable, error) { - b := BuiltinTableBuilder{ - BuiltinTable: BuiltinTable{ +// buildIntrinsicTable builds the IntrinsicTable from the semantic info +func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) { + b := IntrinsicTableBuilder{ + IntrinsicTable: IntrinsicTable{ Sem: s, TMatcherIndex: map[sem.Named]int{}, NMatcherIndex: map[sem.Named]int{}, @@ -359,22 +361,34 @@ func buildBuiltinTable(s *sem.Sem) (*BuiltinTable, error) { b.layoutMatchers(s) - for _, f := range s.Functions { - overloads := make([]Overload, len(f.Overloads)) - overloadDescriptions := make([]string, len(f.Overloads)) - for i, o := range f.Overloads { - overloadDescriptions[i] = fmt.Sprint(o.Decl) - var err error - if overloads[i], err = b.buildOverload(o); err != nil { - return nil, err + buildIntrinsics := func(in []*sem.Intrinsic) ([]Intrinsic, error) { + out := make([]Intrinsic, len(in)) + for i, f := range in { + overloads := make([]Overload, len(f.Overloads)) + overloadDescriptions := make([]string, len(f.Overloads)) + for i, o := range f.Overloads { + overloadDescriptions[i] = fmt.Sprint(o.Decl) + var err error + if overloads[i], err = b.buildOverload(o); err != nil { + return nil, err + } + } + out[i] = Intrinsic{ + Name: f.Name, + OverloadDescriptions: overloadDescriptions, + NumOverloads: len(overloads), + OverloadsOffset: b.lut.overloads.Add(overloads), } } + return out, nil + } - b.Functions = append(b.Functions, Function{ - OverloadDescriptions: overloadDescriptions, - NumOverloads: len(overloads), - OverloadsOffset: b.lut.overloads.Add(overloads), - }) + var err error + if b.Builtins, err = buildIntrinsics(s.Builtins); err != nil { + return nil, err + } + if b.Operators, err = buildIntrinsics(s.Operators); err != nil { + return nil, err } b.lut.matcherIndices.Compact() @@ -383,5 +397,5 @@ func buildBuiltinTable(s *sem.Sem) (*BuiltinTable, error) { b.lut.parameters.Compact() b.lut.overloads.Compact() - return &b.BuiltinTable, nil + return &b.IntrinsicTable, nil } diff --git a/tools/src/cmd/intrinsic-gen/gen/generate.go b/tools/src/cmd/intrinsic-gen/gen/generate.go index 246fb7b853..5d83b19235 100644 --- a/tools/src/cmd/intrinsic-gen/gen/generate.go +++ b/tools/src/cmd/intrinsic-gen/gen/generate.go @@ -29,8 +29,8 @@ type generator struct { s *sem.Sem t *template.Template cached struct { - builtinTable *BuiltinTable // lazily built by builtinTable() - permuter *Permuter // lazily built by permute() + intrinsicTable *IntrinsicTable // lazily built by intrinsicTable() + permuter *Permuter // lazily built by permute() } } @@ -73,7 +73,7 @@ func (g *generator) generate(tmpl string, w io.Writer, writeFile WriteFile) erro "IsDeclarable": isDeclarable, "IsFirstIn": isFirstIn, "IsLastIn": isLastIn, - "BuiltinTable": g.builtinTable, + "IntrinsicTable": g.intrinsicTable, "Permute": g.permute, "Eval": g.eval, "WriteFile": func(relpath, content string) (string, error) { return "", writeFile(relpath, content) }, @@ -121,17 +121,17 @@ func (g *generator) eval(template string, args ...interface{}) (string, error) { return sb.String(), nil } -// builtinTable lazily calls and returns the result of buildBuiltinTable(), +// intrinsicTable lazily calls and returns the result of buildIntrinsicTable(), // caching the result for repeated calls. -func (g *generator) builtinTable() (*BuiltinTable, error) { - if g.cached.builtinTable == nil { +func (g *generator) intrinsicTable() (*IntrinsicTable, error) { + if g.cached.intrinsicTable == nil { var err error - g.cached.builtinTable, err = buildBuiltinTable(g.s) + g.cached.intrinsicTable, err = buildIntrinsicTable(g.s) if err != nil { return nil, err } } - return g.cached.builtinTable, nil + return g.cached.intrinsicTable, nil } // permute lazily calls buildPermuter(), caching the result for repeated diff --git a/tools/src/cmd/intrinsic-gen/gen/permutate.go b/tools/src/cmd/intrinsic-gen/gen/permutate.go index 934e966161..41e6472fa4 100644 --- a/tools/src/cmd/intrinsic-gen/gen/permutate.go +++ b/tools/src/cmd/intrinsic-gen/gen/permutate.go @@ -74,7 +74,7 @@ func (p *Permuter) Permute(overload *sem.Overload) ([]Permutation, error) { permutate := func() error { o := sem.Overload{ Decl: overload.Decl, - Function: overload.Function, + Intrinsic: overload.Intrinsic, CanBeUsedInStage: overload.CanBeUsedInStage, } for i, p := range overload.Parameters { diff --git a/tools/src/cmd/intrinsic-gen/lexer/lexer.go b/tools/src/cmd/intrinsic-gen/lexer/lexer.go index 749ab0d374..35cd73e181 100644 --- a/tools/src/cmd/intrinsic-gen/lexer/lexer.go +++ b/tools/src/cmd/intrinsic-gen/lexer/lexer.go @@ -52,10 +52,6 @@ func (l *lexer) lex() error { l.next() case '\n': l.next() - case '<': - l.tok(1, tok.Lt) - case '>': - l.tok(1, tok.Gt) case '(': l.tok(1, tok.Lparen) case ')': @@ -68,8 +64,14 @@ func (l *lexer) lex() error { l.tok(1, tok.Colon) case ',': l.tok(1, tok.Comma) - case '|': - l.tok(1, tok.Or) + case '*': + l.tok(1, tok.Star) + case '+': + l.tok(1, tok.Plus) + case '%': + l.tok(1, tok.Modulo) + case '^': + l.tok(1, tok.Xor) case '"': start := l.loc l.next() // Skip opening quote @@ -81,13 +83,16 @@ func (l *lexer) lex() error { l.next() // Skip closing quote default: switch { - case l.peek(1) == '/': + case l.peek(0) == '/' && l.peek(1) == '/': l.skip(l.count(toFirst('\n'))) l.next() // Consume newline + case l.match("/", tok.Divide): case l.match("[[", tok.Ldeco): case l.match("]]", tok.Rdeco): case l.match("->", tok.Arrow): + case l.match("-", tok.Minus): case l.match("fn", tok.Function): + case l.match("op", tok.Operator): case l.match("enum", tok.Enum): case l.match("type", tok.Type): case l.match("match", tok.Match): @@ -95,6 +100,19 @@ func (l *lexer) lex() error { l.tok(l.count(alphaNumericOrUnderscore), tok.Identifier) case unicode.IsNumber(l.peek(0)): l.tok(l.count(unicode.IsNumber), tok.Integer) + case l.match("&&", tok.AndAnd): + case l.match("&", tok.And): + case l.match("||", tok.OrOr): + case l.match("|", tok.Or): + case l.match("!=", tok.NotEqual): + case l.match("==", tok.Equal): + case l.match("=", tok.Assign): + case l.match("<<", tok.Shl): + case l.match("<=", tok.Le): + case l.match("<", tok.Lt): + case l.match(">=", tok.Ge): + case l.match(">>", tok.Shr): + case l.match(">", tok.Gt): default: return fmt.Errorf("%v: unexpected '%v'", l.loc, string(l.runes[0])) } diff --git a/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go b/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go index 51130e5d1f..bfc8df8d7b 100644 --- a/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go +++ b/tools/src/cmd/intrinsic-gen/lexer/lexer_test.go @@ -52,6 +52,9 @@ func TestLexTokens(t *testing.T) { {"fn", tok.Token{Kind: tok.Function, Runes: []rune("fn"), Source: tok.Source{ S: loc(1, 1, 0), E: loc(1, 3, 2), }}}, + {"op", tok.Token{Kind: tok.Operator, Runes: []rune("op"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, {"type", tok.Token{Kind: tok.Type, Runes: []rune("type"), Source: tok.Source{ S: loc(1, 1, 0), E: loc(1, 5, 4), }}}, @@ -76,6 +79,45 @@ func TestLexTokens(t *testing.T) { {"}", tok.Token{Kind: tok.Rbrace, Runes: []rune("}"), Source: tok.Source{ S: loc(1, 1, 0), E: loc(1, 2, 1), }}}, + {"&&", tok.Token{Kind: tok.AndAnd, Runes: []rune("&&"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {"&", tok.Token{Kind: tok.And, Runes: []rune("&"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 2, 1), + }}}, + {"||", tok.Token{Kind: tok.OrOr, Runes: []rune("||"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {"|", tok.Token{Kind: tok.Or, Runes: []rune("|"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 2, 1), + }}}, + {"!=", tok.Token{Kind: tok.NotEqual, Runes: []rune("!="), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {"==", tok.Token{Kind: tok.Equal, Runes: []rune("=="), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {"=", tok.Token{Kind: tok.Assign, Runes: []rune("="), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 2, 1), + }}}, + {"<<", tok.Token{Kind: tok.Shl, Runes: []rune("<<"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {"<=", tok.Token{Kind: tok.Le, Runes: []rune("<="), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {"<", tok.Token{Kind: tok.Lt, Runes: []rune("<"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 2, 1), + }}}, + {">=", tok.Token{Kind: tok.Ge, Runes: []rune(">="), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {">>", tok.Token{Kind: tok.Shr, Runes: []rune(">>"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 3, 2), + }}}, + {">", tok.Token{Kind: tok.Gt, Runes: []rune(">"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 2, 1), + }}}, {"[[", tok.Token{Kind: tok.Ldeco, Runes: []rune("[["), Source: tok.Source{ S: loc(1, 1, 0), E: loc(1, 3, 2), }}}, @@ -91,6 +133,9 @@ func TestLexTokens(t *testing.T) { {"|", tok.Token{Kind: tok.Or, Runes: []rune("|"), Source: tok.Source{ S: loc(1, 1, 0), E: loc(1, 2, 1), }}}, + {"*", tok.Token{Kind: tok.Star, Runes: []rune("*"), Source: tok.Source{ + S: loc(1, 1, 0), E: loc(1, 2, 1), + }}}, {"->", tok.Token{Kind: tok.Arrow, Runes: []rune("->"), Source: tok.Source{ S: loc(1, 1, 0), E: loc(1, 3, 2), }}}, @@ -134,10 +179,14 @@ func TestErrors(t *testing.T) { for _, test := range []test{ {" \"abc", "test.txt:1:2 unterminated string"}, {" \"abc\n", "test.txt:1:2 unterminated string"}, - {"*", "test.txt:1:1: unexpected '*'"}, + {"£", "test.txt:1:1: unexpected '£'"}, } { got, err := lexer.Lex([]rune(test.src), "test.txt") - if gotErr := err.Error(); test.expect != gotErr { + gotErr := "" + if err != nil { + gotErr = err.Error() + } + if test.expect != gotErr { t.Errorf(`Lex() returned error "%+v", expected error "%+v"`, gotErr, test.expect) } if got != nil { diff --git a/tools/src/cmd/intrinsic-gen/parser/parser.go b/tools/src/cmd/intrinsic-gen/parser/parser.go index cd775cca4b..48c8a943f7 100644 --- a/tools/src/cmd/intrinsic-gen/parser/parser.go +++ b/tools/src/cmd/intrinsic-gen/parser/parser.go @@ -66,7 +66,10 @@ func (p *parser) parse() (*ast.AST, error) { out.Types = append(out.Types, p.typeDecl(decorations)) decorations = nil case tok.Function: - out.Functions = append(out.Functions, p.functionDecl(decorations)) + out.Builtins = append(out.Builtins, p.builtinDecl(decorations)) + decorations = nil + case tok.Operator: + out.Operators = append(out.Operators, p.operatorDecl(decorations)) decorations = nil default: p.err = fmt.Errorf("%v unexpected token '%v'", t.Source, t.Kind) @@ -153,11 +156,12 @@ func (p *parser) decorations() ast.Decorations { return out } -func (p *parser) functionDecl(decos ast.Decorations) ast.FunctionDecl { +func (p *parser) builtinDecl(decos ast.Decorations) ast.IntrinsicDecl { p.expect(tok.Function, "function declaration") name := p.expect(tok.Identifier, "function name") - f := ast.FunctionDecl{ + f := ast.IntrinsicDecl{ Source: name.Source, + Kind: ast.Builtin, Decorations: decos, Name: string(name.Runes), } @@ -172,6 +176,25 @@ func (p *parser) functionDecl(decos ast.Decorations) ast.FunctionDecl { return f } +func (p *parser) operatorDecl(decos ast.Decorations) ast.IntrinsicDecl { + p.expect(tok.Operator, "operator declaration") + name := p.next() + f := ast.IntrinsicDecl{ + Source: name.Source, + Kind: ast.Operator, + Decorations: decos, + Name: string(name.Runes), + } + if p.peekIs(0, tok.Lt) { + f.TemplateParams = p.templateParams() + } + f.Parameters = p.parameters() + if p.match(tok.Arrow) != nil { + ret := p.templatedName() + f.ReturnType = &ret + } + return f +} func (p *parser) parameters() ast.Parameters { l := ast.Parameters{} p.expect(tok.Lparen, "function parameter list") @@ -270,20 +293,6 @@ func (p *parser) ident(use string) string { return string(p.expect(tok.Identifier, use).Runes) } -// TODO(bclayton): Currently unused, but will be needed for integer bounds -// func (p *parser) integer(use string) int { -// t := p.expect(tok.Integer, use) -// if t.Kind != tok.Integer { -// return 0 -// } -// i, err := strconv.Atoi(string(t.Runes)) -// if err != nil { -// p.err = err -// return 0 -// } -// return i -// } - func (p *parser) match(kind tok.Kind) *tok.Token { if p.err != nil || len(p.tokens) == 0 { return nil @@ -296,6 +305,18 @@ func (p *parser) match(kind tok.Kind) *tok.Token { return &t } +func (p *parser) next() *tok.Token { + if p.err != nil { + return nil + } + if len(p.tokens) == 0 { + p.err = fmt.Errorf("reached end of file") + } + t := p.tokens[0] + p.tokens = p.tokens[1:] + return &t +} + func (p *parser) peekIs(i int, kind tok.Kind) bool { t := p.peek(i) if t == nil { diff --git a/tools/src/cmd/intrinsic-gen/parser/parser_test.go b/tools/src/cmd/intrinsic-gen/parser/parser_test.go index ae78113e70..9ea76c3117 100644 --- a/tools/src/cmd/intrinsic-gen/parser/parser_test.go +++ b/tools/src/cmd/intrinsic-gen/parser/parser_test.go @@ -19,170 +19,369 @@ import ( "dawn.googlesource.com/dawn/tools/src/cmd/intrinsic-gen/ast" "dawn.googlesource.com/dawn/tools/src/cmd/intrinsic-gen/parser" + "dawn.googlesource.com/dawn/tools/src/utils" + "github.com/google/go-cmp/cmp" ) +var ignoreSource = cmp.FilterPath(func(p cmp.Path) bool { + return p.Last().String() == ".Source" +}, cmp.Ignore()) + func TestParser(t *testing.T) { type test struct { - src string - expect ast.AST + location string + src string + expect ast.AST } for _, test := range []test{ - {"enum E {}", ast.AST{ - Enums: []ast.EnumDecl{{Name: "E"}}, - }}, - {"enum E { A [[deco]] B C }", ast.AST{ - Enums: []ast.EnumDecl{{ - Name: "E", - Entries: []ast.EnumEntry{ - {Name: "A"}, - { - Decorations: ast.Decorations{{Name: "deco"}}, - Name: "B", - }, - {Name: "C"}, - }, - }}, - }}, - {"type T", ast.AST{ - Types: []ast.TypeDecl{{Name: "T"}}, - }}, - {"type T", ast.AST{ - Types: []ast.TypeDecl{{ - Name: "T", - TemplateParams: ast.TemplateParams{ - {Name: "A"}, - {Name: "B"}, - {Name: "C"}, - }, - }}, - }}, - {"[[deco]] type T", ast.AST{ - Types: []ast.TypeDecl{{ - Decorations: ast.Decorations{ - {Name: "deco"}, - }, - Name: "T", - }}, - }}, - {`[[deco("a", "b")]] type T`, ast.AST{ - Types: []ast.TypeDecl{{ - Decorations: ast.Decorations{ - {Name: "deco", Values: []string{"a", "b"}}, - }, - Name: "T", - }}, - }}, - {"match M : A", ast.AST{ - Matchers: []ast.MatcherDecl{{ - Name: "M", - Options: ast.MatcherOptions{ - ast.TemplatedName{Name: "A"}, - }, - }}, - }}, - {"match M : A | B", ast.AST{ - Matchers: []ast.MatcherDecl{{ - Name: "M", - Options: ast.MatcherOptions{ - ast.TemplatedName{Name: "A"}, - ast.TemplatedName{Name: "B"}, - }, - }}, - }}, - {"fn F()", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - }}, - }}, - {"[[deco]] fn F()", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - Decorations: ast.Decorations{ - {Name: "deco"}, - }, - }}, - }}, - {"fn F(a)", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - Parameters: ast.Parameters{ - {Type: ast.TemplatedName{Name: "a"}}, - }, - }}, - }}, - {"fn F(a: T)", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - Parameters: ast.Parameters{ - {Name: "a", Type: ast.TemplatedName{Name: "T"}}, - }, - }}, - }}, - {"fn F(a, b)", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - Parameters: ast.Parameters{ - {Type: ast.TemplatedName{Name: "a"}}, - {Type: ast.TemplatedName{Name: "b"}}, - }, - }}, - }}, - {"fn F>()", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - TemplateParams: ast.TemplateParams{ - { - Name: "A", Type: ast.TemplatedName{ + { + utils.ThisLine(), + "enum E {}", + ast.AST{ + Enums: []ast.EnumDecl{{Name: "E"}}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "enum E { A [[deco]] B C }", + ast.AST{ + Enums: []ast.EnumDecl{{ + Name: "E", + Entries: []ast.EnumEntry{ + {Name: "A"}, + { + Decorations: ast.Decorations{{ + Name: "deco", + Values: []string{}, + }}, Name: "B", - TemplateArgs: ast.TemplatedNames{ - {Name: "C"}, + }, + {Name: "C"}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "type T", + ast.AST{ + Types: []ast.TypeDecl{{Name: "T"}}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "type T", + ast.AST{ + Types: []ast.TypeDecl{{ + Name: "T", + TemplateParams: ast.TemplateParams{ + {Name: "A"}, + {Name: "B"}, + {Name: "C"}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "[[deco]] type T", + ast.AST{ + Types: []ast.TypeDecl{{ + Decorations: ast.Decorations{ + {Name: "deco", Values: []string{}}, + }, + Name: "T", + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + `[[deco("a", "b")]] type T`, ast.AST{ + Types: []ast.TypeDecl{{ + Decorations: ast.Decorations{ + {Name: "deco", Values: []string{"a", "b"}}, + }, + Name: "T", + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "match M : A", + ast.AST{ + Matchers: []ast.MatcherDecl{{ + Name: "M", + Options: ast.MatcherOptions{ + ast.TemplatedName{Name: "A"}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "match M : A | B", + ast.AST{ + Matchers: []ast.MatcherDecl{{ + Name: "M", + Options: ast.MatcherOptions{ + ast.TemplatedName{Name: "A"}, + ast.TemplatedName{Name: "B"}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F()", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "[[deco]] fn F()", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + Decorations: ast.Decorations{ + {Name: "deco", Values: []string{}}, + }, + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F(a)", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + Parameters: ast.Parameters{ + {Type: ast.TemplatedName{Name: "a"}}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F(a: T)", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + Parameters: ast.Parameters{ + {Name: "a", Type: ast.TemplatedName{Name: "T"}}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F(a, b)", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + Parameters: ast.Parameters{ + {Type: ast.TemplatedName{Name: "a"}}, + {Type: ast.TemplatedName{Name: "b"}}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F >()", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + TemplateParams: ast.TemplateParams{ + { + Name: "A", Type: ast.TemplatedName{ + Name: "B", + TemplateArgs: ast.TemplatedNames{ + {Name: "C"}, + }, }, }, }, - }, - }}, - }}, - {"fn F(a: X, b: Y)", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - TemplateParams: ast.TemplateParams{ - {Name: "T"}, - }, - Parameters: ast.Parameters{ - {Name: "a", Type: ast.TemplatedName{Name: "X"}}, - {Name: "b", Type: ast.TemplatedName{ - Name: "Y", + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F(a: X, b: Y)", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + TemplateParams: ast.TemplateParams{ + {Name: "T"}, + }, + Parameters: ast.Parameters{ + {Name: "a", Type: ast.TemplatedName{Name: "X"}}, + {Name: "b", Type: ast.TemplatedName{ + Name: "Y", + TemplateArgs: []ast.TemplatedName{{Name: "T"}}, + }}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F() -> X", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + ReturnType: &ast.TemplatedName{Name: "X"}, + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "fn F() -> X", + ast.AST{ + Builtins: []ast.IntrinsicDecl{{ + Kind: ast.Builtin, + Name: "F", + ReturnType: &ast.TemplatedName{ + Name: "X", TemplateArgs: []ast.TemplatedName{{Name: "T"}}, - }}, - }, + }, + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F()", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "[[deco]] op F()", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + Decorations: ast.Decorations{ + {Name: "deco", Values: []string{}}, + }, + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F(a)", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + Parameters: ast.Parameters{ + {Type: ast.TemplatedName{Name: "a"}}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F(a: T)", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + Parameters: ast.Parameters{ + {Name: "a", Type: ast.TemplatedName{Name: "T"}}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F(a, b)", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + Parameters: ast.Parameters{ + {Type: ast.TemplatedName{Name: "a"}}, + {Type: ast.TemplatedName{Name: "b"}}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F >()", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + TemplateParams: ast.TemplateParams{ + { + Name: "A", Type: ast.TemplatedName{ + Name: "B", + TemplateArgs: ast.TemplatedNames{ + {Name: "C"}, + }, + }, + }, + }, + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F(a: X, b: Y)", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + TemplateParams: ast.TemplateParams{ + {Name: "T"}, + }, + Parameters: ast.Parameters{ + {Name: "a", Type: ast.TemplatedName{Name: "X"}}, + {Name: "b", Type: ast.TemplatedName{ + Name: "Y", + TemplateArgs: []ast.TemplatedName{{Name: "T"}}, + }}, + }, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F() -> X", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + ReturnType: &ast.TemplatedName{Name: "X"}, + Parameters: ast.Parameters{}, + }}, + }, + }, { /////////////////////////////////////////////////////////////////// + utils.ThisLine(), + "op F() -> X", + ast.AST{ + Operators: []ast.IntrinsicDecl{{ + Kind: ast.Operator, + Name: "F", + ReturnType: &ast.TemplatedName{ + Name: "X", + TemplateArgs: []ast.TemplatedName{{Name: "T"}}, + }, + Parameters: ast.Parameters{}, + }}, }}, - }}, - {"fn F() -> X", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - ReturnType: &ast.TemplatedName{Name: "X"}, - }}, - }}, - {"fn F() -> X", ast.AST{ - Functions: []ast.FunctionDecl{{ - Name: "F", - ReturnType: &ast.TemplatedName{ - Name: "X", - TemplateArgs: []ast.TemplatedName{{Name: "T"}}, - }, - }}, - }}, } { got, err := parser.Parse(test.src, "file.txt") if err != nil { - t.Errorf("While parsing:\n%s\nParse() returned error: %v", test.src, err) + t.Errorf("\n%v\nWhile parsing:\n%s\nParse() returned error: %v", + test.location, test.src, err) continue } - gotStr, expectStr := got.String(), test.expect.String() - if gotStr != expectStr { - t.Errorf("While parsing:\n%s\nGot:\n%s\nExpected:\n%s", test.src, gotStr, expectStr) + if diff := cmp.Diff(got, &test.expect, ignoreSource); diff != "" { + t.Errorf("\n%v\nWhile parsing:\n%s\n\n%s", + test.location, test.src, diff) } } } @@ -194,10 +393,22 @@ func TestErrors(t *testing.T) { } for _, test := range []test{ - {"+", "test.txt:1:1: unexpected '+'"}, - {"123", "test.txt:1:1 unexpected token 'integer'"}, - {"[[123]]", "test.txt:1:3 expected 'ident' for decoration name, got 'integer'"}, - {"[[abc", "expected ']]' for decoration list, but reached end of file"}, + { + "£", + "test.txt:1:1: unexpected '£'", + }, + { + "123", + "test.txt:1:1 unexpected token 'integer'", + }, + { + "[[123]]", + "test.txt:1:3 expected 'ident' for decoration name, got 'integer'", + }, + { + "[[abc", + "expected ']]' for decoration list, but reached end of file", + }, } { got, err := parser.Parse(test.src, "test.txt") if gotErr := err.Error(); test.expect != gotErr { diff --git a/tools/src/cmd/intrinsic-gen/resolver/resolve.go b/tools/src/cmd/intrinsic-gen/resolver/resolve.go index f7f662adf2..3a09f38d1a 100644 --- a/tools/src/cmd/intrinsic-gen/resolver/resolve.go +++ b/tools/src/cmd/intrinsic-gen/resolver/resolve.go @@ -28,7 +28,8 @@ type resolver struct { s *sem.Sem globals scope - functions map[string]*sem.Function + builtins map[string]*sem.Intrinsic + operators map[string]*sem.Intrinsic enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher } @@ -38,7 +39,8 @@ func Resolve(a *ast.AST) (*sem.Sem, error) { a: a, s: sem.New(), globals: newScope(nil), - functions: map[string]*sem.Function{}, + builtins: map[string]*sem.Intrinsic{}, + operators: map[string]*sem.Intrinsic{}, enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{}, } // Declare and resolve all the enumerators @@ -59,9 +61,15 @@ func Resolve(a *ast.AST) (*sem.Sem, error) { return nil, err } } - // Declare and resolve the functions - for _, f := range a.Functions { - if err := r.function(f); err != nil { + // Declare and resolve the builtins + for _, f := range a.Builtins { + if err := r.intrinsic(f, r.builtins, &r.s.Builtins); err != nil { + return nil, err + } + } + // Declare and resolve the operators + for _, o := range a.Operators { + if err := r.intrinsic(o, r.operators, &r.s.Operators); err != nil { return nil, err } } @@ -220,18 +228,21 @@ func (r *resolver) matcher(a ast.MatcherDecl) error { return fmt.Errorf("'%v' cannot be used for matcher", a.Name) } -// function() resolves a function overload declaration. -// The the first overload for the function creates and appends the sem.Function -// to Sem.Functions. Subsequent overloads append their resolved overload to the -// sem.Function.Overloads list. -func (r *resolver) function(a ast.FunctionDecl) error { - // If this is the first overload of the function, create and register the - // semantic function. - f := r.functions[a.Name] - if f == nil { - f = &sem.Function{Name: a.Name} - r.functions[a.Name] = f - r.s.Functions = append(r.s.Functions, f) +// intrinsic() resolves a intrinsic overload declaration. +// The the first overload for the intrinsic creates and appends the sem.Intrinsic +// to Sem.Intrinsics. Subsequent overloads append their resolved overload to the +// sem.intrinsic.Overloads list. +func (r *resolver) intrinsic( + a ast.IntrinsicDecl, + intrinsicsByName map[string]*sem.Intrinsic, + semIntrinsics *[]*sem.Intrinsic) error { + // If this is the first overload of the intrinsic, create and register the + // semantic intrinsic. + intrinsic := intrinsicsByName[a.Name] + if intrinsic == nil { + intrinsic = &sem.Intrinsic{Name: a.Name} + intrinsicsByName[a.Name] = intrinsic + *semIntrinsics = append(*semIntrinsics, intrinsic) } // Create a new scope for resolving template parameters @@ -246,7 +257,7 @@ func (r *resolver) function(a ast.FunctionDecl) error { // Construct the semantic overload overload := &sem.Overload{ Decl: a, - Function: f, + Intrinsic: intrinsic, Parameters: make([]sem.Parameter, len(a.Parameters)), TemplateParams: templateParams, } @@ -285,8 +296,8 @@ func (r *resolver) function(a ast.FunctionDecl) error { return fmt.Errorf("%v unknown decoration", a.Decorations[0].Source) } - // Append the overload to the function - f.Overloads = append(f.Overloads, overload) + // Append the overload to the intrinsic + intrinsic.Overloads = append(intrinsic.Overloads, overload) // Sort the template parameters by resolved type. Append these to // sem.Overload.OpenTypes or sem.Overload.OpenNumbers based on their kind. @@ -307,6 +318,10 @@ func (r *resolver) function(a ast.FunctionDecl) error { r.s.MaxOpenNumbers = len(overload.OpenNumbers) } + if a.Kind == ast.Operator && (len(a.Parameters) < 1 || len(a.Parameters) > 2) { + return fmt.Errorf("%v operators must have either 1 or 2 parameters", a.Source) + } + // Resolve the parameters for i, p := range a.Parameters { usage, err := r.fullyQualifiedName(&s, p.Type) @@ -495,11 +510,11 @@ func (r *resolver) lookupNamed(s *scope, a ast.TemplatedName) (sem.Named, error) } // calculateUniqueParameterNames() iterates over all the parameters of all -// overloads, calculating the list of unique parameter names +// builtin overloads, calculating the list of unique parameter names func (r *resolver) calculateUniqueParameterNames() []string { set := map[string]struct{}{"": {}} names := []string{} - for _, f := range r.s.Functions { + for _, f := range r.s.Builtins { for _, o := range f.Overloads { for _, p := range o.Parameters { if _, dup := set[p.Name]; !dup { diff --git a/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go b/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go index 1768dbf9f3..9f3aac07bb 100644 --- a/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go +++ b/tools/src/cmd/intrinsic-gen/resolver/resolver_test.go @@ -139,7 +139,7 @@ fn f()`, ` type f32 type T -fn f(T>)`, +fn f(T< T >)`, success, }, { `enum E {A A}`, @@ -299,6 +299,70 @@ fn f(P)`, `file.txt:4:14 cannot use template enum 'E' as template number`, }, { ` +type i +enum e { a } +op << (i) -> e`, + `file.txt:3:14 cannot use 'e' as return type. Must be a type or template type`, + }, { + ` +type T +op << (T)`, + `file.txt:2:10 cannot resolve 'u'`, + }, { + ` +op << ()`, + `file.txt:1:4 operators must have either 1 or 2 parameters`, + }, { + ` +type i +op << (i, i, i)`, + `file.txt:2:4 operators must have either 1 or 2 parameters`, + }, { + ` +type x +op << (T)`, + `file.txt:2:11 'T' template parameters do not accept template arguments`, + }, { + ` +type A +type B +op << (A)`, + `file.txt:3:10 cannot use type 'B' as template number`, + }, { + ` +type A +enum E { b } +op << (A)`, + `file.txt:3:10 cannot use enum entry 'E.b' as template type`, + }, { + ` +type T +type P +match m: T +op << (P)`, + `file.txt:4:10 cannot use type matcher 'm' as template number`, + }, { + ` +type P +enum E { b } +op << (P)`, + `file.txt:3:10 cannot use enum 'E' as template number`, + }, { + ` +type P +enum E { a b } +match m: a | b +op << (P)`, + `file.txt:4:10 cannot use enum matcher 'm' as template number`, + }, { + ` +type P +enum E { a b } +match m: a | b +op << (P)`, + `file.txt:4:16 cannot use template enum 'E' as template number`, + }, { + ` enum E { a } type T`, `file.txt:2:8 invalid template parameter type 'a'`, diff --git a/tools/src/cmd/intrinsic-gen/sem/sem.go b/tools/src/cmd/intrinsic-gen/sem/sem.go index 3d50bc28eb..9a0f973ccb 100644 --- a/tools/src/cmd/intrinsic-gen/sem/sem.go +++ b/tools/src/cmd/intrinsic-gen/sem/sem.go @@ -26,7 +26,8 @@ type Sem struct { Types []*Type TypeMatchers []*TypeMatcher EnumMatchers []*EnumMatcher - Functions []*Function + Builtins []*Intrinsic + Operators []*Intrinsic // Maximum number of open-types used across all builtins MaxOpenTypes int // Maximum number of open-numbers used across all builtins @@ -42,7 +43,8 @@ func New() *Sem { Types: []*Type{}, TypeMatchers: []*TypeMatcher{}, EnumMatchers: []*EnumMatcher{}, - Functions: []*Function{}, + Builtins: []*Intrinsic{}, + Operators: []*Intrinsic{}, } } @@ -121,16 +123,16 @@ type TemplateNumberParam struct { Name string } -// Function describes the overloads of a builtin function -type Function struct { +// Intrinsic describes the overloads of a builtin or operator +type Intrinsic struct { Name string Overloads []*Overload } -// Overload describes a single overload of a function +// Overload describes a single overload of a builtin or operator type Overload struct { - Decl ast.FunctionDecl - Function *Function + Decl ast.IntrinsicDecl + Intrinsic *Intrinsic TemplateParams []TemplateParam OpenTypes []*TemplateTypeParam OpenNumbers []TemplateParam @@ -164,7 +166,13 @@ func (u StageUses) List() []string { // Format implements the fmt.Formatter interface func (o Overload) Format(w fmt.State, verb rune) { - fmt.Fprintf(w, "fn %v", o.Function.Name) + switch o.Decl.Kind { + case ast.Builtin: + fmt.Fprintf(w, "fn ") + case ast.Operator: + fmt.Fprintf(w, "op ") + } + fmt.Fprintf(w, "%v", o.Intrinsic.Name) if len(o.TemplateParams) > 0 { fmt.Fprintf(w, "<") for i, t := range o.TemplateParams { diff --git a/tools/src/cmd/intrinsic-gen/tok/tok.go b/tools/src/cmd/intrinsic-gen/tok/tok.go index c15a2359b9..d9e25ad655 100644 --- a/tools/src/cmd/intrinsic-gen/tok/tok.go +++ b/tools/src/cmd/intrinsic-gen/tok/tok.go @@ -29,12 +29,17 @@ const ( String Kind = "string" Match Kind = "match" Function Kind = "fn" + Operator Kind = "op" Type Kind = "type" Enum Kind = "enum" Colon Kind = ":" Comma Kind = "," + Shl Kind = "<<" + Shr Kind = ">>" Lt Kind = "<" + Le Kind = "<=" Gt Kind = ">" + Ge Kind = ">=" Lbrace Kind = "{" Rbrace Kind = "}" Ldeco Kind = "[[" @@ -43,6 +48,18 @@ const ( Rparen Kind = ")" Or Kind = "|" Arrow Kind = "->" + Star Kind = "*" + Divide Kind = "/" + Modulo Kind = "%" + Xor Kind = "^" + Plus Kind = "+" + Minus Kind = "-" + And Kind = "&" + AndAnd Kind = "&&" + OrOr Kind = "||" + NotEqual Kind = "!=" + Equal Kind = "==" + Assign Kind = "=" ) // Invalid represents an invalid token