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_