Add getting constant ID information from Inspector
This also involves a reorganization of the code into its own
subdirectory.
BUG=tint:253
Change-Id: If05018da2662e923e659b485576704f3a6bcd062
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/30340
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index e2a8237..6881312 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -373,8 +373,12 @@
"src/ast/workgroup_decoration.h",
"src/context.cc",
"src/context.h",
- "src/inspector.cc",
- "src/inspector.h",
+ "src/inspector/entry_point.cc",
+ "src/inspector/entry_point.h",
+ "src/inspector/inspector.cc",
+ "src/inspector/inspector.h",
+ "src/inspector/scalar.cc",
+ "src/inspector/scalar.h",
"src/reader/reader.cc",
"src/reader/reader.h",
"src/scope_stack.h",
@@ -757,7 +761,7 @@
"src/ast/variable_decl_statement_test.cc",
"src/ast/variable_test.cc",
"src/ast/workgroup_decoration_test.cc",
- "src/inspector_test.cc",
+ "src/inspector/inspector_test.cc",
"src/scope_stack_test.cc",
"src/transform/bound_array_accessors_transform_test.cc",
"src/transform/vertex_pulling_transform_test.cc",
diff --git a/include/tint/tint.h b/include/tint/tint.h
index 65ba86f..dbbffac 100644
--- a/include/tint/tint.h
+++ b/include/tint/tint.h
@@ -20,6 +20,7 @@
#include "src/ast/pipeline_stage.h"
#include "src/context.h"
+#include "src/inspector/inspector.h"
#include "src/reader/reader.h"
#include "src/transform/bound_array_accessors_transform.h"
#include "src/transform/manager.h"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c4b003f..13a2937 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -194,8 +194,12 @@
ast/workgroup_decoration.h
context.cc
context.h
- inspector.cc
- inspector.h
+ inspector/entry_point.cc
+ inspector/entry_point.h
+ inspector/inspector.cc
+ inspector/inspector.h
+ inspector/scalar.cc
+ inspector/scalar.h
reader/reader.cc
reader/reader.h
scope_stack.h
@@ -367,7 +371,7 @@
ast/variable_decl_statement_test.cc
ast/variable_test.cc
ast/workgroup_decoration_test.cc
- inspector_test.cc
+ inspector/inspector_test.cc
scope_stack_test.cc
transform/bound_array_accessors_transform_test.cc
transform/vertex_pulling_transform_test.cc
diff --git a/src/inspector.cc b/src/inspector.cc
deleted file mode 100644
index cfe9d50..0000000
--- a/src/inspector.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/inspector.h"
-
-#include <algorithm>
-
-#include "src/ast/function.h"
-
-namespace tint {
-namespace inspector {
-
-EntryPoint::EntryPoint() = default;
-EntryPoint::EntryPoint(EntryPoint&) = default;
-EntryPoint::EntryPoint(EntryPoint&&) = default;
-EntryPoint::~EntryPoint() = default;
-
-Inspector::Inspector(const ast::Module& module) : module_(module) {}
-
-Inspector::~Inspector() = default;
-
-std::vector<EntryPoint> Inspector::GetEntryPoints() {
- std::vector<EntryPoint> result;
-
- for (const auto& func : module_.functions()) {
- if (func->IsEntryPoint()) {
- EntryPoint entry_point;
- entry_point.name = func->name();
- entry_point.stage = func->pipeline_stage();
- std::tie(entry_point.workgroup_size_x, entry_point.workgroup_size_y,
- entry_point.workgroup_size_z) = func->workgroup_size();
-
- for (auto* var : func->referenced_module_variables()) {
- if (var->storage_class() == ast::StorageClass::kInput) {
- entry_point.input_variables.push_back(var->name());
- } else {
- entry_point.output_variables.push_back(var->name());
- }
- }
- result.push_back(std::move(entry_point));
- }
- }
-
- return result;
-}
-
-} // namespace inspector
-} // namespace tint
diff --git a/src/inspector/entry_point.cc b/src/inspector/entry_point.cc
new file mode 100644
index 0000000..eebe27e
--- /dev/null
+++ b/src/inspector/entry_point.cc
@@ -0,0 +1,26 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/inspector/entry_point.h"
+
+namespace tint {
+namespace inspector {
+
+EntryPoint::EntryPoint() = default;
+EntryPoint::EntryPoint(EntryPoint&) = default;
+EntryPoint::EntryPoint(EntryPoint&&) = default;
+EntryPoint::~EntryPoint() = default;
+
+} // namespace inspector
+} // namespace tint
diff --git a/src/inspector.h b/src/inspector/entry_point.h
similarity index 69%
rename from src/inspector.h
rename to src/inspector/entry_point.h
index f39068b..8c3bd73 100644
--- a/src/inspector.h
+++ b/src/inspector/entry_point.h
@@ -12,22 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_INSPECTOR_H_
-#define SRC_INSPECTOR_H_
+#ifndef SRC_INSPECTOR_ENTRY_POINT_H_
+#define SRC_INSPECTOR_ENTRY_POINT_H_
-#include <memory>
-#include <string>
#include <tuple>
#include <vector>
-#include "src/ast/module.h"
#include "src/ast/pipeline_stage.h"
namespace tint {
namespace inspector {
/// Container of reflection data for an entry point in the shader.
-struct EntryPoint {
+typedef struct EntryPoint {
/// Constructors
EntryPoint();
/// Copy Constructor
@@ -56,30 +53,9 @@
return std::tuple<uint32_t, uint32_t, uint32_t>(
workgroup_size_x, workgroup_size_y, workgroup_size_z);
}
-};
-
-/// Extracts information from a module
-class Inspector {
- public:
- /// Constructor
- /// @param module Shader module to extract information from.
- explicit Inspector(const ast::Module& module);
- ~Inspector();
-
- /// @returns error messages from the Inspector
- const std::string& error() { return error_; }
- /// @returns true if an error was encountered
- bool has_error() const { return !error_.empty(); }
-
- /// @returns vector of entry point information
- std::vector<EntryPoint> GetEntryPoints();
-
- private:
- const ast::Module& module_;
- std::string error_;
-};
+} EntryPoint;
} // namespace inspector
} // namespace tint
-#endif // SRC_INSPECTOR_H_
+#endif // SRC_INSPECTOR_ENTRY_POINT_H_
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
new file mode 100644
index 0000000..b5d68f7
--- /dev/null
+++ b/src/inspector/inspector.cc
@@ -0,0 +1,138 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/inspector/inspector.h"
+
+#include <algorithm>
+#include <map>
+
+#include "src/ast/bool_literal.h"
+#include "src/ast/constructor_expression.h"
+#include "src/ast/decorated_variable.h"
+#include "src/ast/float_literal.h"
+#include "src/ast/function.h"
+#include "src/ast/null_literal.h"
+#include "src/ast/scalar_constructor_expression.h"
+#include "src/ast/sint_literal.h"
+#include "src/ast/uint_literal.h"
+
+namespace tint {
+namespace inspector {
+
+Inspector::Inspector(const ast::Module& module) : module_(module) {}
+
+Inspector::~Inspector() = default;
+
+std::vector<EntryPoint> Inspector::GetEntryPoints() {
+ std::vector<EntryPoint> result;
+
+ for (const auto& func : module_.functions()) {
+ if (!func->IsEntryPoint()) {
+ continue;
+ }
+
+ EntryPoint entry_point;
+ entry_point.name = func->name();
+ entry_point.stage = func->pipeline_stage();
+ std::tie(entry_point.workgroup_size_x, entry_point.workgroup_size_y,
+ entry_point.workgroup_size_z) = func->workgroup_size();
+
+ for (auto* var : func->referenced_module_variables()) {
+ if (var->storage_class() == ast::StorageClass::kInput) {
+ entry_point.input_variables.push_back(var->name());
+ } else {
+ entry_point.output_variables.push_back(var->name());
+ }
+ }
+ result.push_back(std::move(entry_point));
+ }
+
+ return result;
+}
+
+std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
+ std::map<uint32_t, Scalar> result;
+ for (auto& var : module_.global_variables()) {
+ if (!var->IsDecorated()) {
+ continue;
+ }
+
+ auto* decorated = var->AsDecorated();
+ if (!decorated->HasConstantIdDecoration()) {
+ continue;
+ }
+
+ // If there are conflicting defintions for a constant id, that is invalid
+ // WGSL, so the validator should catch it. Thus here the inspector just
+ // assumes all definitians of the constant id are the same, so only needs
+ // to find the first reference to constant id.
+ uint32_t constant_id = decorated->constant_id();
+ if (result.find(constant_id) != result.end()) {
+ continue;
+ }
+
+ if (!var->has_constructor()) {
+ result[constant_id] = Scalar();
+ continue;
+ }
+
+ auto* expression = var->constructor();
+ if (!expression->IsConstructor()) {
+ // This is invalid WGSL, but handling gracefully.
+ result[constant_id] = Scalar();
+ continue;
+ }
+
+ auto* constructor = expression->AsConstructor();
+ if (!constructor->IsScalarConstructor()) {
+ // This is invalid WGSL, but handling gracefully.
+ result[constant_id] = Scalar();
+ continue;
+ }
+
+ auto* literal = constructor->AsScalarConstructor()->literal();
+ if (!literal) {
+ // This is invalid WGSL, but handling gracefully.
+ result[constant_id] = Scalar();
+ continue;
+ }
+
+ if (literal->IsBool()) {
+ result[constant_id] = Scalar(literal->AsBool()->IsTrue());
+ continue;
+ }
+
+ if (literal->IsUint()) {
+ result[constant_id] = Scalar(literal->AsUint()->value());
+ continue;
+ }
+
+ if (literal->IsSint()) {
+ result[constant_id] = Scalar(literal->AsSint()->value());
+ continue;
+ }
+
+ if (literal->IsFloat()) {
+ result[constant_id] = Scalar(literal->AsFloat()->value());
+ continue;
+ }
+
+ result[constant_id] = Scalar();
+ }
+
+ return result;
+}
+
+} // namespace inspector
+} // namespace tint
diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h
new file mode 100644
index 0000000..9559fac
--- /dev/null
+++ b/src/inspector/inspector.h
@@ -0,0 +1,59 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_INSPECTOR_INSPECTOR_H_
+#define SRC_INSPECTOR_INSPECTOR_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "src/ast/module.h"
+#include "src/ast/pipeline_stage.h"
+#include "src/inspector/entry_point.h"
+#include "src/inspector/scalar.h"
+
+namespace tint {
+namespace inspector {
+
+/// Extracts information from a module
+class Inspector {
+ public:
+ /// Constructor
+ /// @param module Shader module to extract information from.
+ explicit Inspector(const ast::Module& module);
+ ~Inspector();
+
+ /// @returns error messages from the Inspector
+ const std::string& error() { return error_; }
+ /// @returns true if an error was encountered
+ bool has_error() const { return !error_.empty(); }
+
+ /// @returns vector of entry point information
+ std::vector<EntryPoint> GetEntryPoints();
+
+ /// @returns map of const_id to initial value
+ std::map<uint32_t, Scalar> GetConstantIDs();
+
+ private:
+ const ast::Module& module_;
+ std::string error_;
+};
+
+} // namespace inspector
+} // namespace tint
+
+#endif // SRC_INSPECTOR_INSPECTOR_H_
diff --git a/src/inspector_test.cc b/src/inspector/inspector_test.cc
similarity index 75%
rename from src/inspector_test.cc
rename to src/inspector/inspector_test.cc
index d0a8f96..9a895cc 100644
--- a/src/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -12,23 +12,39 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "src/inspector.h"
+#include "src/inspector/inspector.h"
#include "gtest/gtest.h"
#include "src/ast/assignment_statement.h"
+#include "src/ast/bool_literal.h"
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
+#include "src/ast/constant_id_decoration.h"
+#include "src/ast/decorated_variable.h"
+#include "src/ast/float_literal.h"
#include "src/ast/function.h"
#include "src/ast/identifier_expression.h"
+#include "src/ast/null_literal.h"
#include "src/ast/pipeline_stage.h"
#include "src/ast/return_statement.h"
+#include "src/ast/scalar_constructor_expression.h"
+#include "src/ast/sint_literal.h"
#include "src/ast/stage_decoration.h"
+#include "src/ast/type/bool_type.h"
+#include "src/ast/type/f32_type.h"
+#include "src/ast/type/i32_type.h"
+#include "src/ast/type/type.h"
#include "src/ast/type/u32_type.h"
#include "src/ast/type/void_type.h"
+#include "src/ast/uint_literal.h"
+#include "src/ast/variable_decl_statement.h"
+#include "src/ast/variable_decoration.h"
#include "src/ast/workgroup_decoration.h"
#include "src/context.h"
#include "src/type_determiner.h"
+#include "tint/tint.h"
+
namespace tint {
namespace inspector {
namespace {
@@ -140,6 +156,59 @@
return func;
}
+ /// Add a Constant ID to the global variables.
+ /// @param name name of the variable to add
+ /// @param id id number for the constant id
+ /// @param type type of the variable
+ /// @param val value to initialize the variable with, if NULL no initializer
+ /// will be added.
+ template <class T>
+ void CreateConstantID(std::string name,
+ uint32_t id,
+ ast::type::Type* type,
+ T* val) {
+ auto dvar = std::make_unique<ast::DecoratedVariable>(
+ std::make_unique<ast::Variable>(name, ast::StorageClass::kNone, type));
+ dvar->set_is_const(true);
+ ast::VariableDecorationList decos;
+ decos.push_back(std::make_unique<ast::ConstantIdDecoration>(id));
+ dvar->set_decorations(std::move(decos));
+ if (val) {
+ dvar->set_constructor(std::make_unique<ast::ScalarConstructorExpression>(
+ MakeLiteral<T>(type, val)));
+ }
+ mod()->AddGlobalVariable(std::move(dvar));
+ }
+
+ template <class T>
+ std::unique_ptr<ast::Literal> MakeLiteral(ast::type::Type*, T*) {
+ return nullptr;
+ }
+
+ template <>
+ std::unique_ptr<ast::Literal> MakeLiteral<bool>(ast::type::Type* type,
+ bool* val) {
+ return std::make_unique<ast::BoolLiteral>(type, *val);
+ }
+
+ template <>
+ std::unique_ptr<ast::Literal> MakeLiteral<uint32_t>(ast::type::Type* type,
+ uint32_t* val) {
+ return std::make_unique<ast::UintLiteral>(type, *val);
+ }
+
+ template <>
+ std::unique_ptr<ast::Literal> MakeLiteral<int32_t>(ast::type::Type* type,
+ int32_t* val) {
+ return std::make_unique<ast::SintLiteral>(type, *val);
+ }
+
+ template <>
+ std::unique_ptr<ast::Literal> MakeLiteral<float>(ast::type::Type* type,
+ float* val) {
+ return std::make_unique<ast::FloatLiteral>(type, *val);
+ }
+
bool ContainsString(const std::vector<std::string>& vec,
const std::string& str) {
for (auto& s : vec) {
@@ -154,8 +223,11 @@
TypeDeterminer* td() { return td_.get(); }
Inspector* inspector() { return inspector_.get(); }
- ast::type::VoidType* void_type() { return &void_type_; }
+ ast::type::BoolType* bool_type() { return &bool_type_; }
+ ast::type::F32Type* f32_type() { return &f32_type_; }
+ ast::type::I32Type* i32_type() { return &i32_type_; }
ast::type::U32Type* u32_type() { return &u32_type_; }
+ ast::type::VoidType* void_type() { return &void_type_; }
private:
Context ctx_;
@@ -163,8 +235,11 @@
std::unique_ptr<TypeDeterminer> td_;
std::unique_ptr<Inspector> inspector_;
- ast::type::VoidType void_type_;
+ ast::type::BoolType bool_type_;
+ ast::type::F32Type f32_type_;
+ ast::type::I32Type i32_type_;
ast::type::U32Type u32_type_;
+ ast::type::VoidType void_type_;
};
class InspectorTest : public InspectorHelper, public testing::Test {};
@@ -494,6 +569,94 @@
EXPECT_EQ("out2_var", result[1].output_variables[0]);
}
+TEST_F(InspectorGetEntryPointTest, BoolConstantIDs) {
+ bool val_true = true;
+ bool val_false = false;
+ CreateConstantID<bool>("foo", 1, bool_type(), nullptr);
+ CreateConstantID<bool>("bar", 20, bool_type(), &val_true);
+ CreateConstantID<bool>("baz", 300, bool_type(), &val_false);
+
+ auto result = inspector()->GetConstantIDs();
+ ASSERT_EQ(3u, result.size());
+
+ ASSERT_TRUE(result.find(1) != result.end());
+ EXPECT_TRUE(result[1].IsNull());
+
+ ASSERT_TRUE(result.find(20) != result.end());
+ EXPECT_TRUE(result[20].IsBool());
+ EXPECT_TRUE(result[20].AsBool());
+
+ ASSERT_TRUE(result.find(300) != result.end());
+ EXPECT_TRUE(result[300].IsBool());
+ EXPECT_FALSE(result[300].AsBool());
+}
+
+TEST_F(InspectorGetEntryPointTest, U32ConstantIDs) {
+ uint32_t val = 42;
+ CreateConstantID<uint32_t>("foo", 1, u32_type(), nullptr);
+ CreateConstantID<uint32_t>("bar", 20, u32_type(), &val);
+
+ auto result = inspector()->GetConstantIDs();
+ ASSERT_EQ(2u, result.size());
+
+ ASSERT_TRUE(result.find(1) != result.end());
+ EXPECT_TRUE(result[1].IsNull());
+
+ ASSERT_TRUE(result.find(20) != result.end());
+ EXPECT_TRUE(result[20].IsU32());
+ EXPECT_EQ(42u, result[20].AsU32());
+}
+
+TEST_F(InspectorGetEntryPointTest, I32ConstantIDs) {
+ int32_t val_neg = -42;
+ int32_t val_pos = 42;
+ CreateConstantID<int32_t>("foo", 1, i32_type(), nullptr);
+ CreateConstantID<int32_t>("bar", 20, i32_type(), &val_neg);
+ CreateConstantID<int32_t>("baz", 300, i32_type(), &val_pos);
+
+ auto result = inspector()->GetConstantIDs();
+ ASSERT_EQ(3u, result.size());
+
+ ASSERT_TRUE(result.find(1) != result.end());
+ EXPECT_TRUE(result[1].IsNull());
+
+ ASSERT_TRUE(result.find(20) != result.end());
+ EXPECT_TRUE(result[20].IsI32());
+ EXPECT_EQ(-42, result[20].AsI32());
+
+ ASSERT_TRUE(result.find(300) != result.end());
+ EXPECT_TRUE(result[300].IsI32());
+ EXPECT_EQ(42, result[300].AsI32());
+}
+
+TEST_F(InspectorGetEntryPointTest, FloatConstantIDs) {
+ float val_zero = 0.0f;
+ float val_neg = -10.0f;
+ float val_pos = 15.0f;
+ CreateConstantID<float>("foo", 1, f32_type(), nullptr);
+ CreateConstantID<float>("bar", 20, f32_type(), &val_zero);
+ CreateConstantID<float>("baz", 300, f32_type(), &val_neg);
+ CreateConstantID<float>("x", 4000, f32_type(), &val_pos);
+
+ auto result = inspector()->GetConstantIDs();
+ ASSERT_EQ(4u, result.size());
+
+ ASSERT_TRUE(result.find(1) != result.end());
+ EXPECT_TRUE(result[1].IsNull());
+
+ ASSERT_TRUE(result.find(20) != result.end());
+ EXPECT_TRUE(result[20].IsFloat());
+ EXPECT_FLOAT_EQ(0.0, result[20].AsFloat());
+
+ ASSERT_TRUE(result.find(300) != result.end());
+ EXPECT_TRUE(result[300].IsFloat());
+ EXPECT_FLOAT_EQ(-10.0, result[300].AsFloat());
+
+ ASSERT_TRUE(result.find(4000) != result.end());
+ EXPECT_TRUE(result[4000].IsFloat());
+ EXPECT_FLOAT_EQ(15.0, result[4000].AsFloat());
+}
+
} // namespace
} // namespace inspector
} // namespace tint
diff --git a/src/inspector/scalar.cc b/src/inspector/scalar.cc
new file mode 100644
index 0000000..cc1ce78
--- /dev/null
+++ b/src/inspector/scalar.cc
@@ -0,0 +1,75 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/inspector/scalar.h"
+
+namespace tint {
+namespace inspector {
+
+Scalar::Scalar() : type_(kNull) {}
+
+Scalar::Scalar(bool val) : type_(kBool) {
+ value_.b = val;
+}
+
+Scalar::Scalar(uint32_t val) : type_(kU32) {
+ value_.u = val;
+}
+
+Scalar::Scalar(int32_t val) : type_(kI32) {
+ value_.i = val;
+}
+
+Scalar::Scalar(float val) : type_(kFloat) {
+ value_.f = val;
+}
+
+bool Scalar::IsNull() const {
+ return type_ == kNull;
+}
+
+bool Scalar::IsBool() const {
+ return type_ == kBool;
+}
+
+bool Scalar::IsU32() const {
+ return type_ == kU32;
+}
+
+bool Scalar::IsI32() const {
+ return type_ == kI32;
+}
+
+bool Scalar::IsFloat() const {
+ return type_ == kFloat;
+}
+
+bool Scalar::AsBool() const {
+ return value_.b;
+}
+
+uint32_t Scalar::AsU32() const {
+ return value_.u;
+}
+
+int32_t Scalar::AsI32() const {
+ return value_.i;
+}
+
+float Scalar::AsFloat() const {
+ return value_.f;
+}
+
+} // namespace inspector
+} // namespace tint
diff --git a/src/inspector/scalar.h b/src/inspector/scalar.h
new file mode 100644
index 0000000..4768b94
--- /dev/null
+++ b/src/inspector/scalar.h
@@ -0,0 +1,80 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_INSPECTOR_SCALAR_H_
+#define SRC_INSPECTOR_SCALAR_H_
+
+#include <cstdint>
+
+namespace tint {
+namespace inspector {
+
+/// Contains a literal scalar value
+class Scalar {
+ public:
+ /// Null Constructor
+ Scalar();
+ /// @param val literal scalar value to contain
+ explicit Scalar(bool val);
+ /// @param val literal scalar value to contain
+ explicit Scalar(uint32_t val);
+ /// @param val literal scalar value to contain
+ explicit Scalar(int32_t val);
+ /// @param val literal scalar value to contain
+ explicit Scalar(float val);
+
+ /// @returns true if this is a null
+ bool IsNull() const;
+ /// @returns true if this is a bool
+ bool IsBool() const;
+ /// @returns true if this is a unsigned integer.
+ bool IsU32() const;
+ /// @returns true if this is a signed integer.
+ bool IsI32() const;
+ /// @returns true if this is a float.
+ bool IsFloat() const;
+
+ /// @returns scalar value if bool, otherwise undefined behaviour.
+ bool AsBool() const;
+ /// @returns scalar value if unsigned integer, otherwise undefined behaviour.
+ uint32_t AsU32() const;
+ /// @returns scalar value if signed integer, otherwise undefined behaviour.
+ int32_t AsI32() const;
+ /// @returns scalar value if float, otherwise undefined behaviour.
+ float AsFloat() const;
+
+ private:
+ typedef enum {
+ kNull,
+ kBool,
+ kU32,
+ kI32,
+ kFloat,
+ } Type;
+
+ typedef union {
+ bool b;
+ uint32_t u;
+ int32_t i;
+ float f;
+ } Value;
+
+ Type type_;
+ Value value_;
+};
+
+} // namespace inspector
+} // namespace tint
+
+#endif // SRC_INSPECTOR_SCALAR_H_