Initial commit
diff --git a/src/ast/array_accessor_expression.cc b/src/ast/array_accessor_expression.cc
new file mode 100644
index 0000000..a98b436
--- /dev/null
+++ b/src/ast/array_accessor_expression.cc
@@ -0,0 +1,49 @@
+// 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/ast/array_accessor_expression.h"
+
+namespace tint {
+namespace ast {
+
+ArrayAccessorExpression::ArrayAccessorExpression(
+    std::unique_ptr<Expression> array,
+    std::unique_ptr<Expression> idx_expr)
+    : Expression(), array_(std::move(array)), idx_expr_(std::move(idx_expr)) {}
+
+ArrayAccessorExpression::ArrayAccessorExpression(
+    const Source& source,
+    std::unique_ptr<Expression> array,
+    std::unique_ptr<Expression> idx_expr)
+    : Expression(source),
+      array_(std::move(array)),
+      idx_expr_(std::move(idx_expr)) {}
+
+ArrayAccessorExpression::~ArrayAccessorExpression() = default;
+
+bool ArrayAccessorExpression::IsValid() const {
+  return array_ != nullptr && idx_expr_ != nullptr;
+}
+
+void ArrayAccessorExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "ArrayAccessor{" << std::endl;
+  array_->to_str(out, indent + 2);
+  idx_expr_->to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/array_accessor_expression.h b/src/ast/array_accessor_expression.h
new file mode 100644
index 0000000..ddffdee
--- /dev/null
+++ b/src/ast/array_accessor_expression.h
@@ -0,0 +1,83 @@
+// 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_AST_ARRAY_ACCESSOR_EXPRESSION_H_
+#define SRC_AST_ARRAY_ACCESSOR_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// An array accessor expression
+class ArrayAccessorExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param array the array
+  /// @param idx_expr the index expression
+  ArrayAccessorExpression(std::unique_ptr<Expression> array,
+                          std::unique_ptr<Expression> idx_expr);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param array the array
+  /// @param idx_expr the index expression
+  ArrayAccessorExpression(const Source& source,
+                          std::unique_ptr<Expression> array,
+                          std::unique_ptr<Expression> idx_expr);
+  /// Move constructor
+  ArrayAccessorExpression(ArrayAccessorExpression&&) = default;
+  ~ArrayAccessorExpression() override;
+
+  /// Sets the array
+  /// @param array the array
+  void set_array(std::unique_ptr<Expression> array) {
+    array_ = std::move(array);
+  }
+  /// @returns the array
+  Expression* array() const { return array_.get(); }
+
+  /// Sets the index expression
+  /// @param idx_expr the index expression
+  void set_idx_expr(std::unique_ptr<Expression> idx_expr) {
+    idx_expr_ = std::move(idx_expr);
+  }
+  /// @returns the index expression
+  Expression* idx_expr() const { return idx_expr_.get(); }
+
+  /// @returns true if this is an array accessor expression
+  bool IsArrayAccessor() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  ArrayAccessorExpression(const ArrayAccessorExpression&) = delete;
+
+  std::unique_ptr<Expression> array_;
+  std::unique_ptr<Expression> idx_expr_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_ARRAY_ACCESSOR_EXPRESSION_H_
diff --git a/src/ast/as_expression.cc b/src/ast/as_expression.cc
new file mode 100644
index 0000000..deb9564
--- /dev/null
+++ b/src/ast/as_expression.cc
@@ -0,0 +1,41 @@
+// 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/ast/as_expression.h"
+
+namespace tint {
+namespace ast {
+
+AsExpression::AsExpression(type::Type* type, std::unique_ptr<Expression> expr)
+    : Expression(), type_(type), expr_(std::move(expr)) {}
+
+AsExpression::AsExpression(const Source& source,
+                           type::Type* type,
+                           std::unique_ptr<Expression> expr)
+    : Expression(source), type_(type), expr_(std::move(expr)) {}
+
+AsExpression::~AsExpression() = default;
+
+bool AsExpression::IsValid() const {
+  return type_ != nullptr && expr_ != nullptr;
+}
+
+void AsExpression::to_str(std::ostream& out, size_t indent) const {
+  out << "as<" << type_->type_name() << ">(";
+  expr_->to_str(out, indent);
+  out << ")";
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/as_expression.h b/src/ast/as_expression.h
new file mode 100644
index 0000000..93036f8
--- /dev/null
+++ b/src/ast/as_expression.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_AST_AS_EXPRESSION_H_
+#define SRC_AST_AS_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+
+/// An as expression
+class AsExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param type the type
+  /// @param expr the expr
+  AsExpression(type::Type* type, std::unique_ptr<Expression> expr);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param type the type
+  /// @param expr the expr
+  AsExpression(const Source& source,
+               type::Type* type,
+               std::unique_ptr<Expression> expr);
+  /// Move constructor
+  AsExpression(AsExpression&&) = default;
+  ~AsExpression() override;
+
+  /// Sets the type
+  /// @param type the type
+  void set_type(type::Type* type) { type_ = std::move(type); }
+  /// @returns the left side expression
+  type::Type* type() const { return type_; }
+
+  /// Sets the expr
+  /// @param expr the expression
+  void set_expr(std::unique_ptr<Expression> expr) { expr_ = std::move(expr); }
+  /// @returns the expression
+  Expression* expr() const { return expr_.get(); }
+
+  /// @returns true if this is an as expression
+  bool IsAs() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  AsExpression(const AsExpression&) = delete;
+
+  type::Type* type_;
+  std::unique_ptr<Expression> expr_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_AS_EXPRESSION_H_
diff --git a/src/ast/assignment_statement.cc b/src/ast/assignment_statement.cc
new file mode 100644
index 0000000..8fe711b
--- /dev/null
+++ b/src/ast/assignment_statement.cc
@@ -0,0 +1,47 @@
+// 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/ast/assignment_statement.h"
+
+namespace tint {
+namespace ast {
+
+AssignmentStatement::AssignmentStatement(std::unique_ptr<Expression> lhs,
+                                         std::unique_ptr<Expression> rhs)
+    : Statement(), lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+
+AssignmentStatement::AssignmentStatement(const Source& source,
+                                         std::unique_ptr<Expression> lhs,
+                                         std::unique_ptr<Expression> rhs)
+    : Statement(source), lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+
+AssignmentStatement::~AssignmentStatement() = default;
+
+bool AssignmentStatement::IsValid() const {
+  return lhs_ != nullptr && rhs_ != nullptr;
+}
+
+void AssignmentStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Assignment{" << std::endl;
+  lhs_->to_str(out, indent + 2);
+  out << std::endl;
+  rhs_->to_str(out, indent + 2);
+  out << std::endl;
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/assignment_statement.h b/src/ast/assignment_statement.h
new file mode 100644
index 0000000..6441874
--- /dev/null
+++ b/src/ast/assignment_statement.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_AST_ASSIGNMENT_STATEMENT_H_
+#define SRC_AST_ASSIGNMENT_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// An assignment statement
+class AssignmentStatement : public Statement {
+ public:
+  /// Constructor
+  /// @param lhs the left side of the expression
+  /// @param rhs the right side of the expression
+  AssignmentStatement(std::unique_ptr<Expression> lhs,
+                      std::unique_ptr<Expression> rhs);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param lhs the left side of the expression
+  /// @param rhs the right side of the expression
+  AssignmentStatement(const Source& source,
+                      std::unique_ptr<Expression> lhs,
+                      std::unique_ptr<Expression> rhs);
+  /// Move constructor
+  AssignmentStatement(AssignmentStatement&&) = default;
+  ~AssignmentStatement() override;
+
+  /// Sets the left side of the statement
+  /// @param lhs the left side to set
+  void set_lhs(std::unique_ptr<Expression> lhs) { lhs_ = std::move(lhs); }
+  /// @returns the left side expression
+  Expression* lhs() const { return lhs_.get(); }
+
+  /// Sets the right side of the statement
+  /// @param rhs the right side to set
+  void set_rhs(std::unique_ptr<Expression> rhs) { rhs_ = std::move(rhs); }
+  /// @returns the right side expression
+  Expression* rhs() const { return rhs_.get(); }
+
+  /// @returns true if this is an assignment statement
+  bool IsAssign() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  AssignmentStatement(const AssignmentStatement&) = delete;
+
+  std::unique_ptr<Expression> lhs_;
+  std::unique_ptr<Expression> rhs_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_ASSIGNMENT_STATEMENT_H_
diff --git a/src/ast/binding_decoration.cc b/src/ast/binding_decoration.cc
new file mode 100644
index 0000000..4278dd5
--- /dev/null
+++ b/src/ast/binding_decoration.cc
@@ -0,0 +1,29 @@
+// 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/ast/binding_decoration.h"
+
+namespace tint {
+namespace ast {
+
+BindingDecoration::BindingDecoration(size_t val) : value_(val) {}
+
+BindingDecoration::~BindingDecoration() = default;
+
+void BindingDecoration::to_str(std::ostream& out) const {
+  out << "binding " << value_;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/binding_decoration.h b/src/ast/binding_decoration.h
new file mode 100644
index 0000000..1a7e573
--- /dev/null
+++ b/src/ast/binding_decoration.h
@@ -0,0 +1,50 @@
+// 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_AST_BINDING_DECORATION_H_
+#define SRC_AST_BINDING_DECORATION_H_
+
+#include <stddef.h>
+
+#include "src/ast/variable_decoration.h"
+
+namespace tint {
+namespace ast {
+
+/// A binding decoration
+class BindingDecoration : public VariableDecoration {
+ public:
+  /// constructor
+  /// @param value the binding value
+  explicit BindingDecoration(size_t value);
+  ~BindingDecoration() override;
+
+  /// @returns true if this is a binding decoration
+  bool IsBinding() const override { return true; }
+
+  /// @returns the binding value
+  size_t value() const { return value_; }
+
+  /// Outputs the decoration to the given stream
+  /// @param out the stream to output too
+  void to_str(std::ostream& out) const override;
+
+ private:
+  size_t value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_BINDING_DECORATION_H_
diff --git a/src/ast/binding_decoration_test.cc b/src/ast/binding_decoration_test.cc
new file mode 100644
index 0000000..0a6a57b
--- /dev/null
+++ b/src/ast/binding_decoration_test.cc
@@ -0,0 +1,38 @@
+// 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/ast/binding_decoration.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using BindingDecorationTest = testing::Test;
+
+TEST_F(BindingDecorationTest, Creation) {
+  BindingDecoration d{2};
+  EXPECT_EQ(2, d.value());
+}
+
+TEST_F(BindingDecorationTest, Is) {
+  BindingDecoration d{2};
+  EXPECT_TRUE(d.IsBinding());
+  EXPECT_FALSE(d.IsBuiltin());
+  EXPECT_FALSE(d.IsLocation());
+  EXPECT_FALSE(d.IsSet());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/bool_literal.cc b/src/ast/bool_literal.cc
new file mode 100644
index 0000000..e11e8a5
--- /dev/null
+++ b/src/ast/bool_literal.cc
@@ -0,0 +1,29 @@
+// 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/ast/bool_literal.h"
+
+namespace tint {
+namespace ast {
+
+BoolLiteral::BoolLiteral(bool value) : value_(value) {}
+
+BoolLiteral::~BoolLiteral() = default;
+
+std::string BoolLiteral::to_str() const {
+  return value_ ? "true" : "false";
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/bool_literal.h b/src/ast/bool_literal.h
new file mode 100644
index 0000000..c568f27
--- /dev/null
+++ b/src/ast/bool_literal.h
@@ -0,0 +1,51 @@
+// 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_AST_BOOL_LITERAL_H_
+#define SRC_AST_BOOL_LITERAL_H_
+
+#include <string>
+
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A boolean literal
+class BoolLiteral : public Literal {
+ public:
+  /// Constructor
+  /// @param value the bool literals value
+  explicit BoolLiteral(bool value);
+  ~BoolLiteral() override;
+
+  /// @returns true if this is a bool literal
+  bool IsBool() const override { return true; }
+
+  /// @returns true if the bool literal is true
+  bool IsTrue() const { return value_; }
+  /// @returns true if the bool literal is false
+  bool IsFalse() const { return !value_; }
+
+  /// @returns the literal as a string
+  std::string to_str() const override;
+
+ private:
+  bool value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_BOOL_LITERAL_H_
diff --git a/src/ast/bool_literal_test.cc b/src/ast/bool_literal_test.cc
new file mode 100644
index 0000000..af01dae
--- /dev/null
+++ b/src/ast/bool_literal_test.cc
@@ -0,0 +1,55 @@
+// 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/ast/bool_literal.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using BoolLiteralTest = testing::Test;
+
+TEST_F(BoolLiteralTest, True) {
+  BoolLiteral b{true};
+  ASSERT_TRUE(b.IsBool());
+  ASSERT_TRUE(b.IsTrue());
+  ASSERT_FALSE(b.IsFalse());
+}
+
+TEST_F(BoolLiteralTest, False) {
+  BoolLiteral b{false};
+  ASSERT_TRUE(b.IsBool());
+  ASSERT_FALSE(b.IsTrue());
+  ASSERT_TRUE(b.IsFalse());
+}
+
+TEST_F(BoolLiteralTest, Is) {
+  BoolLiteral b{false};
+  EXPECT_TRUE(b.IsBool());
+  EXPECT_FALSE(b.IsInt());
+  EXPECT_FALSE(b.IsFloat());
+  EXPECT_FALSE(b.IsUint());
+}
+
+TEST_F(BoolLiteralTest, ToStr) {
+  BoolLiteral t{true};
+  BoolLiteral f{false};
+
+  EXPECT_EQ(t.to_str(), "true");
+  EXPECT_EQ(f.to_str(), "false");
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/break_statement.cc b/src/ast/break_statement.cc
new file mode 100644
index 0000000..a095e7d
--- /dev/null
+++ b/src/ast/break_statement.cc
@@ -0,0 +1,58 @@
+// 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/ast/break_statement.h"
+
+namespace tint {
+namespace ast {
+
+BreakStatement::BreakStatement(StatementCondition condition,
+                               std::unique_ptr<Expression> conditional)
+    : Statement(),
+      condition_(condition),
+      conditional_(std::move(conditional)) {}
+
+BreakStatement::BreakStatement(const Source& source,
+                               StatementCondition condition,
+                               std::unique_ptr<Expression> conditional)
+    : Statement(source),
+      condition_(condition),
+      conditional_(std::move(conditional)) {}
+
+BreakStatement::~BreakStatement() = default;
+
+bool BreakStatement::IsValid() const {
+  return condition_ == StatementCondition::kNone || conditional_ != nullptr;
+}
+
+void BreakStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Break";
+
+  if (condition_ != StatementCondition::kNone) {
+    out << "{" << std::endl;
+
+    make_indent(out, indent + 2);
+    out << condition_ << std::endl;
+    conditional_->to_str(out, indent + 2);
+
+    make_indent(out, indent);
+    out << "}";
+  }
+
+  out << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/break_statement.h b/src/ast/break_statement.h
new file mode 100644
index 0000000..9795bd3
--- /dev/null
+++ b/src/ast/break_statement.h
@@ -0,0 +1,84 @@
+// 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_AST_BREAK_STATEMENT_H_
+#define SRC_AST_BREAK_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+#include "src/ast/statement_condition.h"
+
+namespace tint {
+namespace ast {
+
+/// An break statement
+class BreakStatement : public Statement {
+ public:
+  /// Constructor
+  BreakStatement();
+  /// Constructor
+  /// @param condition the condition type
+  /// @param conditional the condition expression
+  BreakStatement(StatementCondition condition,
+                 std::unique_ptr<Expression> conditional);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param condition the condition type
+  /// @param conditional the condition expression
+  BreakStatement(const Source& source,
+                 StatementCondition condition,
+                 std::unique_ptr<Expression> conditional);
+  /// Move constructor
+  BreakStatement(BreakStatement&&) = default;
+  ~BreakStatement() override;
+
+  /// Sets the condition type
+  /// @param condition the condition type
+  void set_condition(StatementCondition condition) { condition_ = condition; }
+  /// @returns the condition type
+  StatementCondition condition() const { return condition_; }
+
+  /// Sets the conditional expression
+  /// @param conditional the conditional expression
+  void set_conditional(std::unique_ptr<Expression> conditional) {
+    conditional_ = std::move(conditional);
+  }
+  /// @returns the conditional expression
+  Expression* conditional() const { return conditional_.get(); }
+
+  /// @returns true if this is an break statement
+  bool IsBreak() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  BreakStatement(const BreakStatement&) = delete;
+
+  StatementCondition condition_ = StatementCondition::kNone;
+  std::unique_ptr<Expression> conditional_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_BREAK_STATEMENT_H_
diff --git a/src/ast/builtin.cc b/src/ast/builtin.cc
new file mode 100644
index 0000000..e579f9c
--- /dev/null
+++ b/src/ast/builtin.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/ast/builtin.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, Builtin builtin) {
+  switch (builtin) {
+    case Builtin::kNone: {
+      out << "none";
+      break;
+    }
+    case Builtin::kPosition: {
+      out << "position";
+      break;
+    }
+    case Builtin::kVertexIdx: {
+      out << "vertex_idx";
+      break;
+    }
+    case Builtin::kInstanceIdx: {
+      out << "instance_idx";
+      break;
+    }
+    case Builtin::kFrontFacing: {
+      out << "front_facing";
+      break;
+    }
+    case Builtin::kFragCoord: {
+      out << "frag_coord";
+      break;
+    }
+    case Builtin::kFragDepth: {
+      out << "frag_depth";
+      break;
+    }
+    case Builtin::kNumWorkgroups: {
+      out << "num_workgroups";
+      break;
+    }
+    case Builtin::kWorkgroupSize: {
+      out << "workgroup_size";
+      break;
+    }
+    case Builtin::kLocalInvocationId: {
+      out << "local_invocation_id";
+      break;
+    }
+    case Builtin::kLocalInvocationIdx: {
+      out << "local_invocation_idx";
+      break;
+    }
+    case Builtin::kGlobalInvocationId: {
+      out << "global_invocation_id";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/builtin.h b/src/ast/builtin.h
new file mode 100644
index 0000000..511203a
--- /dev/null
+++ b/src/ast/builtin.h
@@ -0,0 +1,44 @@
+// 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_AST_BUILTIN_H_
+#define SRC_AST_BUILTIN_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The builtin identifiers
+enum class Builtin {
+  kNone = -1,
+  kPosition,
+  kVertexIdx,
+  kInstanceIdx,
+  kFrontFacing,
+  kFragCoord,
+  kFragDepth,
+  kNumWorkgroups,
+  kWorkgroupSize,
+  kLocalInvocationId,
+  kLocalInvocationIdx,
+  kGlobalInvocationId
+};
+
+std::ostream& operator<<(std::ostream& out, Builtin builtin);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_BUILTIN_H_
diff --git a/src/ast/builtin_decoration.cc b/src/ast/builtin_decoration.cc
new file mode 100644
index 0000000..c0264af
--- /dev/null
+++ b/src/ast/builtin_decoration.cc
@@ -0,0 +1,29 @@
+// 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/ast/builtin_decoration.h"
+
+namespace tint {
+namespace ast {
+
+BuiltinDecoration::BuiltinDecoration(Builtin builtin) : builtin_(builtin) {}
+
+BuiltinDecoration::~BuiltinDecoration() = default;
+
+void BuiltinDecoration::to_str(std::ostream& out) const {
+  out << "builtin " << builtin_;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/builtin_decoration.h b/src/ast/builtin_decoration.h
new file mode 100644
index 0000000..5027e12
--- /dev/null
+++ b/src/ast/builtin_decoration.h
@@ -0,0 +1,49 @@
+// 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_AST_BUILTIN_DECORATION_H_
+#define SRC_AST_BUILTIN_DECORATION_H_
+
+#include "src/ast/builtin.h"
+#include "src/ast/variable_decoration.h"
+
+namespace tint {
+namespace ast {
+
+/// A builtin decoration
+class BuiltinDecoration : public VariableDecoration {
+ public:
+  /// constructor
+  /// @param builtin the builtin value
+  explicit BuiltinDecoration(Builtin builtin);
+  ~BuiltinDecoration() override;
+
+  /// @returns true if this is a builtin decoration
+  bool IsBuiltin() const override { return true; }
+
+  /// @returns the builtin value
+  Builtin value() const { return builtin_; }
+
+  /// Outputs the decoration to the given stream
+  /// @param out the stream to output too
+  void to_str(std::ostream& out) const override;
+
+ private:
+  Builtin builtin_ = Builtin::kNone;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_BUILTIN_DECORATION_H_
diff --git a/src/ast/builtin_decoration_test.cc b/src/ast/builtin_decoration_test.cc
new file mode 100644
index 0000000..288674e
--- /dev/null
+++ b/src/ast/builtin_decoration_test.cc
@@ -0,0 +1,38 @@
+// 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/ast/builtin_decoration.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using BuiltinDecorationTest = testing::Test;
+
+TEST_F(BuiltinDecorationTest, Creation) {
+  BuiltinDecoration d{Builtin::kFragDepth};
+  EXPECT_EQ(Builtin::kFragDepth, d.value());
+}
+
+TEST_F(BuiltinDecorationTest, Is) {
+  BuiltinDecoration d{Builtin::kFragDepth};
+  EXPECT_FALSE(d.IsBinding());
+  EXPECT_TRUE(d.IsBuiltin());
+  EXPECT_FALSE(d.IsLocation());
+  EXPECT_FALSE(d.IsSet());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/call_expression.cc b/src/ast/call_expression.cc
new file mode 100644
index 0000000..4b0d97d
--- /dev/null
+++ b/src/ast/call_expression.cc
@@ -0,0 +1,47 @@
+// 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/ast/call_expression.h"
+
+namespace tint {
+namespace ast {
+
+CallExpression::CallExpression(std::unique_ptr<Expression> func,
+                               std::vector<std::unique_ptr<Expression>> params)
+    : Expression(), func_(std::move(func)), params_(std::move(params)) {}
+
+CallExpression::CallExpression(const Source& source,
+                               std::unique_ptr<Expression> func,
+                               std::vector<std::unique_ptr<Expression>> params)
+    : Expression(source), func_(std::move(func)), params_(std::move(params)) {}
+
+CallExpression::~CallExpression() = default;
+
+bool CallExpression::IsValid() const {
+  return func_ != nullptr;
+}
+
+void CallExpression::to_str(std::ostream& out, size_t indent) const {
+  func_->to_str(out, indent);
+  make_indent(out, indent + 2);
+  out << "(" << std::endl;
+  for (const auto& param : params_)
+    param->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << ")" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/call_expression.h b/src/ast/call_expression.h
new file mode 100644
index 0000000..ac5178f
--- /dev/null
+++ b/src/ast/call_expression.h
@@ -0,0 +1,84 @@
+// 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_AST_CALL_EXPRESSION_H_
+#define SRC_AST_CALL_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A call expression
+class CallExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param func the function
+  /// @param params the parameters
+  CallExpression(std::unique_ptr<Expression> func,
+                 std::vector<std::unique_ptr<Expression>> params);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param func the function
+  /// @param params the parameters
+  CallExpression(const Source& source,
+                 std::unique_ptr<Expression> func,
+                 std::vector<std::unique_ptr<Expression>> params);
+  /// Move constructor
+  CallExpression(CallExpression&&) = default;
+  ~CallExpression() override;
+
+  /// Sets the func
+  /// @param func the func
+  void set_func(std::unique_ptr<Expression> func) { func_ = std::move(func); }
+  /// @returns the func
+  Expression* func() const { return func_.get(); }
+
+  /// Sets the parameters
+  /// @param params the parameters
+  void set_params(std::vector<std::unique_ptr<Expression>> params) {
+    params_ = std::move(params);
+  }
+  /// @returns the parameters
+  const std::vector<std::unique_ptr<Expression>>& params() const {
+    return params_;
+  }
+
+  /// @returns true if this is a call expression
+  bool IsCall() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  CallExpression(const CallExpression&) = delete;
+
+  std::unique_ptr<Expression> func_;
+  std::vector<std::unique_ptr<Expression>> params_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_CALL_EXPRESSION_H_
diff --git a/src/ast/case_statement.cc b/src/ast/case_statement.cc
new file mode 100644
index 0000000..a591224
--- /dev/null
+++ b/src/ast/case_statement.cc
@@ -0,0 +1,56 @@
+// 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/ast/case_statement.h"
+
+namespace tint {
+namespace ast {
+
+CaseStatement::CaseStatement() : Statement() {}
+
+CaseStatement::CaseStatement(std::unique_ptr<Literal> condition,
+                             std::vector<std::unique_ptr<Statement>> body)
+    : Statement(), condition_(std::move(condition)), body_(std::move(body)) {}
+
+CaseStatement::CaseStatement(const Source& source,
+                             std::unique_ptr<Literal> condition,
+                             std::vector<std::unique_ptr<Statement>> body)
+    : Statement(source),
+      condition_(std::move(condition)),
+      body_(std::move(body)) {}
+
+CaseStatement::~CaseStatement() = default;
+
+bool CaseStatement::IsValid() const {
+  return true;
+}
+
+void CaseStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+
+  if (IsDefault()) {
+    out << "default{" << std::endl;
+  } else {
+    out << "Case " << condition_->to_str() << "{" << std::endl;
+  }
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 2);
+
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/case_statement.h b/src/ast/case_statement.h
new file mode 100644
index 0000000..8a3ae09
--- /dev/null
+++ b/src/ast/case_statement.h
@@ -0,0 +1,90 @@
+// 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_AST_CASE_STATEMENT_H_
+#define SRC_AST_CASE_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/statement.h"
+#include "src/ast/statement_condition.h"
+
+namespace tint {
+namespace ast {
+
+/// A case statement
+class CaseStatement : public Statement {
+ public:
+  /// Constructor
+  CaseStatement();
+  /// Constructor
+  /// @param condition the case condition
+  /// @param body the case body
+  CaseStatement(std::unique_ptr<Literal> condition,
+                std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param source the source information
+  /// @param condition the case condition
+  /// @param body the case body
+  CaseStatement(const Source& source,
+                std::unique_ptr<Literal> condition,
+                std::vector<std::unique_ptr<Statement>> body);
+  /// Move constructor
+  CaseStatement(CaseStatement&&) = default;
+  ~CaseStatement() override;
+
+  /// Sets the condition for the case statement
+  /// @param condition the condition to set
+  void set_condition(std::unique_ptr<Literal> condition) {
+    condition_ = std::move(condition);
+  }
+  /// @returns the case condition or nullptr if none set
+  Literal* condition() const { return condition_.get(); }
+  /// @returns true if this is a default statement
+  bool IsDefault() const { return condition_ == nullptr; }
+
+  /// Sets the case body
+  /// @param body the case body
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the case body
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// @returns true if this is a case statement
+  bool IsCase() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  CaseStatement(const CaseStatement&) = delete;
+
+  std::unique_ptr<Literal> condition_;
+  std::vector<std::unique_ptr<Statement>> body_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_CASE_STATEMENT_H_
diff --git a/src/ast/cast_expression.cc b/src/ast/cast_expression.cc
new file mode 100644
index 0000000..1d52350
--- /dev/null
+++ b/src/ast/cast_expression.cc
@@ -0,0 +1,42 @@
+// 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/ast/cast_expression.h"
+
+namespace tint {
+namespace ast {
+
+CastExpression::CastExpression(type::Type* type,
+                               std::unique_ptr<Expression> expr)
+    : Expression(), type_(type), expr_(std::move(expr)) {}
+
+CastExpression::CastExpression(const Source& source,
+                               type::Type* type,
+                               std::unique_ptr<Expression> expr)
+    : Expression(source), type_(type), expr_(std::move(expr)) {}
+
+CastExpression::~CastExpression() = default;
+
+bool CastExpression::IsValid() const {
+  return type_ != nullptr && expr_ != nullptr;
+}
+
+void CastExpression::to_str(std::ostream& out, size_t indent) const {
+  out << "cast<" << type_->type_name() << ">(";
+  expr_->to_str(out, indent);
+  out << ")";
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/cast_expression.h b/src/ast/cast_expression.h
new file mode 100644
index 0000000..dcb8a3f
--- /dev/null
+++ b/src/ast/cast_expression.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_AST_CAST_EXPRESSION_H_
+#define SRC_AST_CAST_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+
+/// A cast expression
+class CastExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param type the type
+  /// @param expr the expr
+  CastExpression(type::Type* type, std::unique_ptr<Expression> expr);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param type the type
+  /// @param expr the expr
+  CastExpression(const Source& source,
+                 type::Type* type,
+                 std::unique_ptr<Expression> expr);
+  /// Move constructor
+  CastExpression(CastExpression&&) = default;
+  ~CastExpression() override;
+
+  /// Sets the type
+  /// @param type the type
+  void set_type(type::Type* type) { type_ = std::move(type); }
+  /// @returns the left side expression
+  type::Type* type() const { return type_; }
+
+  /// Sets the expr
+  /// @param expr the expression
+  void set_expr(std::unique_ptr<Expression> expr) { expr_ = std::move(expr); }
+  /// @returns the expression
+  Expression* expr() const { return expr_.get(); }
+
+  /// @returns true if this is a cast expression
+  bool IsCast() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  CastExpression(const CastExpression&) = delete;
+
+  type::Type* type_;
+  std::unique_ptr<Expression> expr_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_CAST_EXPRESSION_H_
diff --git a/src/ast/const_initializer_expression.cc b/src/ast/const_initializer_expression.cc
new file mode 100644
index 0000000..11f1880
--- /dev/null
+++ b/src/ast/const_initializer_expression.cc
@@ -0,0 +1,42 @@
+// 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/ast/const_initializer_expression.h"
+
+namespace tint {
+namespace ast {
+
+ConstInitializerExpression::ConstInitializerExpression(
+    std::unique_ptr<Literal> literal)
+    : InitializerExpression(), literal_(std::move(literal)) {}
+
+ConstInitializerExpression::ConstInitializerExpression(
+    const Source& source,
+    std::unique_ptr<Literal> litearl)
+    : InitializerExpression(source), literal_(std::move(litearl)) {}
+
+ConstInitializerExpression::~ConstInitializerExpression() = default;
+
+bool ConstInitializerExpression::IsValid() const {
+  return literal_ != nullptr;
+}
+
+void ConstInitializerExpression::to_str(std::ostream& out,
+                                        size_t indent) const {
+  make_indent(out, indent);
+  out << "ConstInitializer{" << literal_->to_str() << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/const_initializer_expression.h b/src/ast/const_initializer_expression.h
new file mode 100644
index 0000000..31e2d44
--- /dev/null
+++ b/src/ast/const_initializer_expression.h
@@ -0,0 +1,70 @@
+// 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_AST_CONST_INITIALIZER_EXPRESSION_H_
+#define SRC_AST_CONST_INITIALIZER_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/initializer_expression.h"
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A constant initializer
+class ConstInitializerExpression : public InitializerExpression {
+ public:
+  /// Constructor
+  /// @param literal the const literal
+  explicit ConstInitializerExpression(std::unique_ptr<Literal> literal);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param literal the const literal
+  ConstInitializerExpression(const Source& source,
+                             std::unique_ptr<Literal> literal);
+  /// Move constructor
+  ConstInitializerExpression(ConstInitializerExpression&&) = default;
+  ~ConstInitializerExpression() override;
+
+  /// @returns true if this is a constant initializer
+  bool IsConstInitializer() const override { return true; }
+
+  /// Set the literal value
+  /// @param literal the literal
+  void set_literal(std::unique_ptr<Literal> literal) {
+    literal_ = std::move(literal);
+  }
+  /// @returns the literal value
+  Literal* literal() const { return literal_.get(); }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  ConstInitializerExpression(const ConstInitializerExpression&) = delete;
+
+  std::unique_ptr<Literal> literal_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_CONST_INITIALIZER_EXPRESSION_H_
diff --git a/src/ast/continue_statement.cc b/src/ast/continue_statement.cc
new file mode 100644
index 0000000..e154455
--- /dev/null
+++ b/src/ast/continue_statement.cc
@@ -0,0 +1,57 @@
+// 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/ast/continue_statement.h"
+
+namespace tint {
+namespace ast {
+
+ContinueStatement::ContinueStatement(StatementCondition condition,
+                                     std::unique_ptr<Expression> conditional)
+    : Statement(),
+      condition_(condition),
+      conditional_(std::move(conditional)) {}
+
+ContinueStatement::ContinueStatement(const Source& source,
+                                     StatementCondition condition,
+                                     std::unique_ptr<Expression> conditional)
+    : Statement(source),
+      condition_(condition),
+      conditional_(std::move(conditional)) {}
+
+ContinueStatement::~ContinueStatement() = default;
+
+bool ContinueStatement::IsValid() const {
+  return condition_ == StatementCondition::kNone || conditional_ != nullptr;
+}
+
+void ContinueStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Continue";
+
+  if (condition_ != StatementCondition::kNone) {
+    out << "{" << std::endl;
+
+    make_indent(out, indent + 2);
+    out << condition_ << std::endl;
+    conditional_->to_str(out, indent + 2);
+
+    make_indent(out, indent);
+    out << "}";
+  }
+  out << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/continue_statement.h b/src/ast/continue_statement.h
new file mode 100644
index 0000000..8cadbb7
--- /dev/null
+++ b/src/ast/continue_statement.h
@@ -0,0 +1,84 @@
+// 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_AST_CONTINUE_STATEMENT_H_
+#define SRC_AST_CONTINUE_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+#include "src/ast/statement_condition.h"
+
+namespace tint {
+namespace ast {
+
+/// An continue statement
+class ContinueStatement : public Statement {
+ public:
+  /// Constructor
+  ContinueStatement();
+  /// Constructor
+  /// @param condition the condition type
+  /// @param conditional the condition expression
+  ContinueStatement(StatementCondition condition,
+                    std::unique_ptr<Expression> conditional);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param condition the condition type
+  /// @param conditional the condition expression
+  ContinueStatement(const Source& source,
+                    StatementCondition condition,
+                    std::unique_ptr<Expression> conditional);
+  /// Move constructor
+  ContinueStatement(ContinueStatement&&) = default;
+  ~ContinueStatement() override;
+
+  /// Sets the condition type
+  /// @param condition the condition type
+  void set_condition(StatementCondition condition) { condition_ = condition; }
+  /// @returns the condition type
+  StatementCondition condition() const { return condition_; }
+
+  /// Sets the conditional expression
+  /// @param conditional the conditional expression
+  void set_conditional(std::unique_ptr<Expression> conditional) {
+    conditional_ = std::move(conditional);
+  }
+  /// @returns the conditional expression
+  Expression* conditional() const { return conditional_.get(); }
+
+  /// @returns true if this is an continue statement
+  bool IsContinue() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  ContinueStatement(const ContinueStatement&) = delete;
+
+  StatementCondition condition_ = StatementCondition::kNone;
+  std::unique_ptr<Expression> conditional_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_CONTINUE_STATEMENT_H_
diff --git a/src/ast/decorated_variable.cc b/src/ast/decorated_variable.cc
new file mode 100644
index 0000000..2a6b42e
--- /dev/null
+++ b/src/ast/decorated_variable.cc
@@ -0,0 +1,51 @@
+// 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/ast/decorated_variable.h"
+
+namespace tint {
+namespace ast {
+
+DecoratedVariable::DecoratedVariable() = default;
+
+DecoratedVariable::DecoratedVariable(DecoratedVariable&&) = default;
+
+DecoratedVariable::~DecoratedVariable() = default;
+
+bool DecoratedVariable::IsValid() const {
+  return Variable::IsValid();
+}
+
+void DecoratedVariable::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "DecoratedVariable{" << std::endl;
+
+  make_indent(out, indent + 2);
+  out << "decorations{" << std::endl;
+  for (const auto& deco : decorations_) {
+    make_indent(out, indent + 4);
+    deco->to_str(out);
+    out << std::endl;
+  }
+
+  make_indent(out, indent + 2);
+  out << "}" << std::endl;
+
+  info_to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/decorated_variable.h b/src/ast/decorated_variable.h
new file mode 100644
index 0000000..d81de81
--- /dev/null
+++ b/src/ast/decorated_variable.h
@@ -0,0 +1,67 @@
+// 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_AST_DECORATED_VARIABLE_H_
+#define SRC_AST_DECORATED_VARIABLE_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/variable.h"
+#include "src/ast/variable_decoration.h"
+
+namespace tint {
+namespace ast {
+
+/// A Decorated Variable statement.
+class DecoratedVariable : public Variable {
+ public:
+  /// Create a new empty decorated variable statement
+  DecoratedVariable();
+  /// Move constructor
+  DecoratedVariable(DecoratedVariable&&);
+
+  ~DecoratedVariable() override;
+
+  /// Sets a decoration to the variable
+  /// @param decos the decorations to set
+  void set_decorations(std::vector<std::unique_ptr<VariableDecoration>> decos) {
+    decorations_ = std::move(decos);
+  }
+  /// @returns the decorations attached to this variable
+  const std::vector<std::unique_ptr<VariableDecoration>>& decorations() const {
+    return decorations_;
+  }
+
+  /// @returns true if this is a decorated variable
+  bool IsDecorated() const override { return true; }
+
+  /// @returns true if the name and path are both present
+  bool IsValid() const override;
+
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  DecoratedVariable(const DecoratedVariable&) = delete;
+
+  std::vector<std::unique_ptr<VariableDecoration>> decorations_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_DECORATED_VARIABLE_H_
diff --git a/src/ast/derivative_modifier.cc b/src/ast/derivative_modifier.cc
new file mode 100644
index 0000000..66a7f35
--- /dev/null
+++ b/src/ast/derivative_modifier.cc
@@ -0,0 +1,39 @@
+// 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/ast/derivative_modifier.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, DerivativeModifier mod) {
+  switch (mod) {
+    case DerivativeModifier::kNone: {
+      out << "none";
+      break;
+    }
+    case DerivativeModifier::kFine: {
+      out << "fine";
+      break;
+    }
+    case DerivativeModifier::kCoarse: {
+      out << "coarse";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/derivative_modifier.h b/src/ast/derivative_modifier.h
new file mode 100644
index 0000000..83789e4
--- /dev/null
+++ b/src/ast/derivative_modifier.h
@@ -0,0 +1,31 @@
+// 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_AST_DERIVATIVE_MODIFIER_H_
+#define SRC_AST_DERIVATIVE_MODIFIER_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The derivative modifier
+enum class DerivativeModifier { kNone = -1, kFine, kCoarse };
+
+std::ostream& operator<<(std::ostream& out, DerivativeModifier mod);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_DERIVATIVE_MODIFIER_H_
diff --git a/src/ast/else_statement.cc b/src/ast/else_statement.cc
new file mode 100644
index 0000000..e41f61b
--- /dev/null
+++ b/src/ast/else_statement.cc
@@ -0,0 +1,63 @@
+// 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/ast/else_statement.h"
+
+namespace tint {
+namespace ast {
+
+ElseStatement::ElseStatement() : Statement() {}
+
+ElseStatement::ElseStatement(std::vector<std::unique_ptr<Statement>> body)
+    : Statement(), body_(std::move(body)) {}
+
+ElseStatement::ElseStatement(std::unique_ptr<Expression> condition,
+                             std::vector<std::unique_ptr<Statement>> body)
+    : Statement(), condition_(std::move(condition)), body_(std::move(body)) {}
+
+ElseStatement::ElseStatement(const Source& source,
+                             std::vector<std::unique_ptr<Statement>> body)
+    : Statement(source), body_(std::move(body)) {}
+
+ElseStatement::ElseStatement(const Source& source,
+                             std::unique_ptr<Expression> condition,
+                             std::vector<std::unique_ptr<Statement>> body)
+    : Statement(source),
+      condition_(std::move(condition)),
+      body_(std::move(body)) {}
+
+ElseStatement::~ElseStatement() = default;
+
+bool ElseStatement::IsValid() const {
+  return true;
+}
+
+void ElseStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Else{" << std::endl;
+  if (condition_ != nullptr)
+    condition_->to_str(out, indent + 2);
+
+  make_indent(out, indent + 2);
+  out << "{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/else_statement.h b/src/ast/else_statement.h
new file mode 100644
index 0000000..66511f3
--- /dev/null
+++ b/src/ast/else_statement.h
@@ -0,0 +1,96 @@
+// 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_AST_ELSE_STATEMENT_H_
+#define SRC_AST_ELSE_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// An else statement
+class ElseStatement : public Statement {
+ public:
+  /// Constructor
+  ElseStatement();
+  /// Constructor
+  /// @param body the else body
+  explicit ElseStatement(std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param condition the else condition
+  /// @param body the else body
+  ElseStatement(std::unique_ptr<Expression> condition,
+                std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param source the source information
+  /// @param body the else body
+  ElseStatement(const Source& source,
+                std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param source the source information
+  /// @param condition the else condition
+  /// @param body the else body
+  ElseStatement(const Source& source,
+                std::unique_ptr<Expression> condition,
+                std::vector<std::unique_ptr<Statement>> body);
+  /// Move constructor
+  ElseStatement(ElseStatement&&) = default;
+  ~ElseStatement() override;
+
+  /// Sets the condition for the else statement
+  /// @param condition the condition to set
+  void set_condition(std::unique_ptr<Expression> condition) {
+    condition_ = std::move(condition);
+  }
+  /// @returns the else condition or nullptr if none set
+  Expression* condition() const { return condition_.get(); }
+  /// @returns true if the else has a condition
+  bool HasCondition() const { return condition_ != nullptr; }
+
+  /// Sets the else body
+  /// @param body the else body
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the else body
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// @returns true if this is a else statement
+  bool IsElse() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  ElseStatement(const ElseStatement&) = delete;
+
+  std::unique_ptr<Expression> condition_;
+  std::vector<std::unique_ptr<Statement>> body_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_ELSE_STATEMENT_H_
diff --git a/src/ast/entry_point.cc b/src/ast/entry_point.cc
new file mode 100644
index 0000000..a433be1
--- /dev/null
+++ b/src/ast/entry_point.cc
@@ -0,0 +1,50 @@
+// 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/ast/entry_point.h"
+
+namespace tint {
+namespace ast {
+
+EntryPoint::EntryPoint(PipelineStage stage,
+                       const std::string& name,
+                       const std::string& fn_name)
+    : Node(), stage_(stage), name_(name), fn_name_(fn_name) {}
+
+EntryPoint::EntryPoint(const Source& source,
+                       PipelineStage stage,
+                       const std::string& name,
+                       const std::string& fn_name)
+    : Node(source), stage_(stage), name_(name), fn_name_(fn_name) {}
+
+EntryPoint::~EntryPoint() = default;
+
+bool EntryPoint::IsValid() const {
+  if (stage_ == PipelineStage::kNone) {
+    return false;
+  }
+  if (fn_name_.length() == 0) {
+    return false;
+  }
+  return true;
+}
+
+void EntryPoint::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << R"(EntryPoint{")" << stage_ << R"(" as ")" << name_ << R"(" = )"
+      << fn_name_ << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/entry_point.h b/src/ast/entry_point.h
new file mode 100644
index 0000000..40ca20f
--- /dev/null
+++ b/src/ast/entry_point.h
@@ -0,0 +1,89 @@
+// 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_AST_ENTRY_POINT_H_
+#define SRC_AST_ENTRY_POINT_H_
+
+#include <ostream>
+#include <string>
+
+#include "src/ast/node.h"
+#include "src/ast/pipeline_stage.h"
+
+namespace tint {
+namespace ast {
+
+/// An entry point statement.
+class EntryPoint : public Node {
+ public:
+  /// Constructor
+  EntryPoint() = default;
+  /// Constructor
+  /// @param stage the entry point stage
+  /// @param name the entry point name
+  /// @param fn_name the function name
+  EntryPoint(PipelineStage stage,
+             const std::string& name,
+             const std::string& fn_name);
+  /// Constructor
+  /// @param source the source of the entry point
+  /// @param stage the entry point stage
+  /// @param name the entry point name
+  /// @param fn_name the function name
+  EntryPoint(const Source& source,
+             PipelineStage stage,
+             const std::string& name,
+             const std::string& fn_name);
+  /// Move constructor
+  EntryPoint(EntryPoint&&) = default;
+
+  ~EntryPoint() override;
+
+  /// Sets the entry point name
+  /// @param name the name to set
+  void set_name(const std::string& name) { name_ = name; }
+  /// @returns the entry points name
+  const std::string& name() const { return name_; }
+  /// Sets the entry point function name
+  /// @param name the function name
+  void set_function_name(const std::string& name) { fn_name_ = name; }
+  /// @returns the function name for the entry point
+  const std::string& function_name() const { return fn_name_; }
+  /// Sets the piepline stage
+  /// @param stage the stage to set
+  void set_pipeline_stage(PipelineStage stage) { stage_ = stage; }
+  /// @returns the pipeline stage for the entry point
+  PipelineStage stage() const { return stage_; }
+
+  /// @returns true if the entry point is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the entry point to the output stream
+  /// @param out the stream to write too
+  /// @param indent number of spaces to ident the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  EntryPoint(const EntryPoint&) = delete;
+
+  Source source_;
+  PipelineStage stage_;
+  std::string name_;
+  std::string fn_name_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_ENTRY_POINT_H_
diff --git a/src/ast/entry_point_test.cc b/src/ast/entry_point_test.cc
new file mode 100644
index 0000000..5765924
--- /dev/null
+++ b/src/ast/entry_point_test.cc
@@ -0,0 +1,91 @@
+// 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/ast/entry_point.h"
+
+#include <sstream>
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using EntryPointTest = testing::Test;
+
+TEST_F(EntryPointTest, Creation) {
+  EntryPoint e(PipelineStage::kVertex, "main", "vtx_main");
+
+  EXPECT_EQ(e.name(), "main");
+  EXPECT_EQ(e.function_name(), "vtx_main");
+  EXPECT_EQ(e.stage(), PipelineStage::kVertex);
+  EXPECT_EQ(e.line(), 0);
+  EXPECT_EQ(e.column(), 0);
+}
+
+TEST_F(EntryPointTest, CreationWithSource) {
+  Source s{27, 4};
+  EntryPoint e(s, PipelineStage::kVertex, "main", "vtx_main");
+
+  EXPECT_EQ(e.name(), "main");
+  EXPECT_EQ(e.function_name(), "vtx_main");
+  EXPECT_EQ(e.stage(), PipelineStage::kVertex);
+  EXPECT_EQ(e.line(), 27);
+  EXPECT_EQ(e.column(), 4);
+}
+
+TEST_F(EntryPointTest, CreationEmpty) {
+  Source s{27, 4};
+  EntryPoint e;
+  e.set_source(s);
+  e.set_pipeline_stage(PipelineStage::kFragment);
+  e.set_function_name("my_func");
+  e.set_name("a_name");
+
+  EXPECT_EQ(e.function_name(), "my_func");
+  EXPECT_EQ(e.name(), "a_name");
+  EXPECT_EQ(e.stage(), PipelineStage::kFragment);
+  EXPECT_EQ(e.line(), 27);
+  EXPECT_EQ(e.column(), 4);
+}
+
+TEST_F(EntryPointTest, to_str) {
+  EntryPoint e(PipelineStage::kVertex, "text", "vtx_main");
+  std::ostringstream out;
+  e.to_str(out, 0);
+  EXPECT_EQ(out.str(), R"(EntryPoint{"vertex" as "text" = vtx_main}
+)");
+}
+
+TEST_F(EntryPointTest, IsValid) {
+  EntryPoint e(PipelineStage::kVertex, "main", "vtx_main");
+  EXPECT_TRUE(e.IsValid());
+}
+
+TEST_F(EntryPointTest, IsValid_MissingFunctionName) {
+  EntryPoint e(PipelineStage::kVertex, "main", "");
+  EXPECT_FALSE(e.IsValid());
+}
+
+TEST_F(EntryPointTest, IsValid_MissingStage) {
+  EntryPoint e(PipelineStage::kNone, "main", "fn");
+  EXPECT_FALSE(e.IsValid());
+}
+
+TEST_F(EntryPointTest, IsValid_MissingBoth) {
+  EntryPoint e;
+  EXPECT_FALSE(e.IsValid());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/expression.cc b/src/ast/expression.cc
new file mode 100644
index 0000000..78041d6
--- /dev/null
+++ b/src/ast/expression.cc
@@ -0,0 +1,96 @@
+// 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/ast/expression.h"
+
+#include <assert.h>
+
+#include "src/ast/array_accessor_expression.h"
+#include "src/ast/as_expression.h"
+#include "src/ast/call_expression.h"
+#include "src/ast/cast_expression.h"
+#include "src/ast/identifier_expression.h"
+#include "src/ast/initializer_expression.h"
+#include "src/ast/member_accessor_expression.h"
+#include "src/ast/relational_expression.h"
+#include "src/ast/unary_derivative_expression.h"
+#include "src/ast/unary_method_expression.h"
+#include "src/ast/unary_op_expression.h"
+
+namespace tint {
+namespace ast {
+
+Expression::Expression() = default;
+
+Expression::Expression(const Source& source) : Node(source) {}
+
+Expression::~Expression() = default;
+
+ArrayAccessorExpression* Expression::AsArrayAccessor() {
+  assert(IsArrayAccessor());
+  return static_cast<ArrayAccessorExpression*>(this);
+}
+
+AsExpression* Expression::AsAs() {
+  assert(IsAs());
+  return static_cast<AsExpression*>(this);
+}
+
+CallExpression* Expression::AsCall() {
+  assert(IsCall());
+  return static_cast<CallExpression*>(this);
+}
+
+CastExpression* Expression::AsCast() {
+  assert(IsCast());
+  return static_cast<CastExpression*>(this);
+}
+
+IdentifierExpression* Expression::AsIdentifier() {
+  assert(IsIdentifier());
+  return static_cast<IdentifierExpression*>(this);
+}
+
+InitializerExpression* Expression::AsInitializer() {
+  assert(IsInitializer());
+  return static_cast<InitializerExpression*>(this);
+}
+
+MemberAccessorExpression* Expression::AsMemberAccessor() {
+  assert(IsMemberAccessor());
+  return static_cast<MemberAccessorExpression*>(this);
+}
+
+RelationalExpression* Expression::AsRelational() {
+  assert(IsRelational());
+  return static_cast<RelationalExpression*>(this);
+}
+
+UnaryDerivativeExpression* Expression::AsUnaryDerivative() {
+  assert(IsUnaryDerivative());
+  return static_cast<UnaryDerivativeExpression*>(this);
+}
+
+UnaryMethodExpression* Expression::AsUnaryMethod() {
+  assert(IsUnaryMethod());
+  return static_cast<UnaryMethodExpression*>(this);
+}
+
+UnaryOpExpression* Expression::AsUnaryOp() {
+  assert(IsUnaryOp());
+  return static_cast<UnaryOpExpression*>(this);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/expression.h b/src/ast/expression.h
new file mode 100644
index 0000000..ebc694b
--- /dev/null
+++ b/src/ast/expression.h
@@ -0,0 +1,102 @@
+// 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_AST_EXPRESSION_H_
+#define SRC_AST_EXPRESSION_H_
+
+#include "src/ast/node.h"
+
+namespace tint {
+namespace ast {
+
+class ArrayAccessorExpression;
+class AsExpression;
+class CallExpression;
+class CastExpression;
+class IdentifierExpression;
+class InitializerExpression;
+class MemberAccessorExpression;
+class RelationalExpression;
+class UnaryDerivativeExpression;
+class UnaryMethodExpression;
+class UnaryOpExpression;
+
+/// Base expression class
+class Expression : public Node {
+ public:
+  ~Expression() override;
+
+  /// @returns true if this is an array accessor expression
+  virtual bool IsArrayAccessor() const { return false; }
+  /// @returns true if this is an as expression
+  virtual bool IsAs() const { return false; }
+  /// @returns true if this is a call expression
+  virtual bool IsCall() const { return false; }
+  /// @returns true if this is a cast expression
+  virtual bool IsCast() const { return false; }
+  /// @returns true if this is an identifier expression
+  virtual bool IsIdentifier() const { return false; }
+  /// @returns true if this is an initializer expression
+  virtual bool IsInitializer() const { return false; }
+  /// @returns true if this is a member accessor expression
+  virtual bool IsMemberAccessor() const { return false; }
+  /// @returns true if this is a relational expression
+  virtual bool IsRelational() const { return false; }
+  /// @returns true if this is a unary derivative expression
+  virtual bool IsUnaryDerivative() const { return false; }
+  /// @returns true if this is a unary method expression
+  virtual bool IsUnaryMethod() const { return false; }
+  /// @returns true if this is a unary op expression
+  virtual bool IsUnaryOp() const { return false; }
+
+  /// @returns the expression as an array accessor
+  ArrayAccessorExpression* AsArrayAccessor();
+  /// @returns the expression as an as
+  AsExpression* AsAs();
+  /// @returns the expression as a call
+  CallExpression* AsCall();
+  /// @returns the expression as a cast
+  CastExpression* AsCast();
+  /// @returns the expression as an identifier
+  IdentifierExpression* AsIdentifier();
+  /// @returns the expression as an initializer
+  InitializerExpression* AsInitializer();
+  /// @returns the expression as a member accessor
+  MemberAccessorExpression* AsMemberAccessor();
+  /// @returns the expression as a relational expression
+  RelationalExpression* AsRelational();
+  /// @returns the expression as a unary derivative expression
+  UnaryDerivativeExpression* AsUnaryDerivative();
+  /// @returns the expression as a unary method expression
+  UnaryMethodExpression* AsUnaryMethod();
+  /// @returns the expression as a unary op expression
+  UnaryOpExpression* AsUnaryOp();
+
+ protected:
+  /// Constructor
+  Expression();
+  /// Constructor
+  /// @param source the source of the expression
+  explicit Expression(const Source& source);
+  /// Move constructor
+  Expression(Expression&&) = default;
+
+ private:
+  Expression(const Expression&) = delete;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_EXPRESSION_H_
diff --git a/src/ast/fallthrough_statement.cc b/src/ast/fallthrough_statement.cc
new file mode 100644
index 0000000..f5ddcea
--- /dev/null
+++ b/src/ast/fallthrough_statement.cc
@@ -0,0 +1,37 @@
+// 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/ast/fallthrough_statement.h"
+
+namespace tint {
+namespace ast {
+
+FallthroughStatement::FallthroughStatement() : Statement() {}
+
+FallthroughStatement::FallthroughStatement(const Source& source)
+    : Statement(source) {}
+
+FallthroughStatement::~FallthroughStatement() = default;
+
+bool FallthroughStatement::IsValid() const {
+  return true;
+}
+
+void FallthroughStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Fallthrough" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/fallthrough_statement.h b/src/ast/fallthrough_statement.h
new file mode 100644
index 0000000..34cd092
--- /dev/null
+++ b/src/ast/fallthrough_statement.h
@@ -0,0 +1,58 @@
+// 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_AST_FALLTHROUGH_STATEMENT_H_
+#define SRC_AST_FALLTHROUGH_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+#include "src/ast/statement_condition.h"
+
+namespace tint {
+namespace ast {
+
+/// An fallthrough statement
+class FallthroughStatement : public Statement {
+ public:
+  /// Constructor
+  FallthroughStatement();
+  /// Constructor
+  /// @param source the source information
+  explicit FallthroughStatement(const Source& source);
+  /// Move constructor
+  FallthroughStatement(FallthroughStatement&&) = default;
+  ~FallthroughStatement() override;
+
+  /// @returns true if this is an fallthrough statement
+  bool IsFallthrough() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  FallthroughStatement(const FallthroughStatement&) = delete;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_FALLTHROUGH_STATEMENT_H_
diff --git a/src/ast/float_literal.cc b/src/ast/float_literal.cc
new file mode 100644
index 0000000..1d8b40f
--- /dev/null
+++ b/src/ast/float_literal.cc
@@ -0,0 +1,29 @@
+// 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/ast/float_literal.h"
+
+namespace tint {
+namespace ast {
+
+FloatLiteral::FloatLiteral(float value) : value_(value) {}
+
+FloatLiteral::~FloatLiteral() = default;
+
+std::string FloatLiteral::to_str() const {
+  return std::to_string(value_);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/float_literal.h b/src/ast/float_literal.h
new file mode 100644
index 0000000..baf088a
--- /dev/null
+++ b/src/ast/float_literal.h
@@ -0,0 +1,49 @@
+// 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_AST_FLOAT_LITERAL_H_
+#define SRC_AST_FLOAT_LITERAL_H_
+
+#include <string>
+
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A float literal
+class FloatLiteral : public Literal {
+ public:
+  /// Constructor
+  /// @param value the float literals value
+  explicit FloatLiteral(float value);
+  ~FloatLiteral() override;
+
+  /// @returns true if this is a float literal
+  bool IsFloat() const override { return true; }
+
+  /// @returns the float literal value
+  float value() const { return value_; }
+
+  /// @returns the literal as a string
+  std::string to_str() const override;
+
+ private:
+  float value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_FLOAT_LITERAL_H_
diff --git a/src/ast/float_literal_test.cc b/src/ast/float_literal_test.cc
new file mode 100644
index 0000000..8274761
--- /dev/null
+++ b/src/ast/float_literal_test.cc
@@ -0,0 +1,45 @@
+// 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/ast/float_literal.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using FloatLiteralTest = testing::Test;
+
+TEST_F(FloatLiteralTest, Value) {
+  FloatLiteral f{47.2};
+  ASSERT_TRUE(f.IsFloat());
+  EXPECT_EQ(f.value(), 47.2);
+}
+
+TEST_F(FloatLiteralTest, Is) {
+  FloatLiteral f{42};
+  EXPECT_FALSE(f.IsBool());
+  EXPECT_FALSE(f.IsInt());
+  EXPECT_TRUE(f.IsFloat());
+  EXPECT_FALSE(f.IsUint());
+}
+
+TEST_F(FloatLiteralTest, ToStr) {
+  FloatLiteral f{42.1};
+
+  EXPECT_EQ(f.to_str(), "42.1");
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/function.cc b/src/ast/function.cc
new file mode 100644
index 0000000..f53ba0b
--- /dev/null
+++ b/src/ast/function.cc
@@ -0,0 +1,71 @@
+// 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/ast/function.h"
+
+namespace tint {
+namespace ast {
+
+Function::Function(const std::string& name,
+                   std::vector<std::unique_ptr<Variable>> params,
+                   type::Type* return_type)
+    : Node(),
+      name_(name),
+      params_(std::move(params)),
+      return_type_(return_type) {}
+
+Function::Function(const Source& source,
+                   const std::string& name,
+                   std::vector<std::unique_ptr<Variable>> params,
+                   type::Type* return_type)
+    : Node(source),
+      name_(name),
+      params_(std::move(params)),
+      return_type_(return_type) {}
+
+Function::~Function() = default;
+
+bool Function::IsValid() const {
+  if (name_.length() == 0) {
+    return false;
+  }
+  if (return_type_ == nullptr) {
+    return false;
+  }
+  return true;
+}
+
+void Function::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "function -> " << return_type_->type_name() << "{" << std::endl;
+  make_indent(out, indent + 2);
+  out << name_ << std::endl;
+
+  for (const auto& param : params_)
+    param->to_str(out, indent + 2);
+
+  make_indent(out, indent + 2);
+  out << "{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}" << std::endl;
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/function.h b/src/ast/function.h
new file mode 100644
index 0000000..6a1158b
--- /dev/null
+++ b/src/ast/function.h
@@ -0,0 +1,109 @@
+// 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_AST_FUNCTION_H_
+#define SRC_AST_FUNCTION_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/node.h"
+#include "src/ast/statement.h"
+#include "src/ast/type/type.h"
+#include "src/ast/variable.h"
+
+namespace tint {
+namespace ast {
+
+/// A Function statement.
+class Function : public Node {
+ public:
+  /// Create a new empty function statement
+  Function() = default;
+  /// Create a function
+  /// @param name the function name
+  /// @param params the function parameters
+  /// @param return_type the return type
+  Function(const std::string& name,
+           std::vector<std::unique_ptr<Variable>> params,
+           type::Type* return_type);
+  /// Create a function
+  /// @param source the variable source
+  /// @param name the function name
+  /// @param params the function parameters
+  /// @param return_type the return type
+  Function(const Source& source,
+           const std::string& name,
+           std::vector<std::unique_ptr<Variable>> params,
+           type::Type* return_type);
+  /// Move constructor
+  Function(Function&&) = default;
+
+  ~Function() override;
+
+  /// Sets the function name
+  /// @param name the name to set
+  void set_name(const std::string& name) { name_ = name; }
+  /// @returns the function name
+  const std::string& name() { return name_; }
+
+  /// Sets the function parameters
+  /// @param params the function parameters
+  void set_params(std::vector<std::unique_ptr<Variable>> params) {
+    params_ = std::move(params);
+  }
+  /// @returns the function params
+  const std::vector<std::unique_ptr<Variable>>& params() const {
+    return params_;
+  }
+
+  /// Sets the return type of the function
+  /// @param type the return type
+  void set_return_type(type::Type* type) { return_type_ = type; }
+  /// @returns the function return type.
+  type::Type* return_type() const { return return_type_; }
+
+  /// Sets the body of the function
+  /// @param body the function body
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the function body
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// @returns true if the name and path are both present
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  Function(const Function&) = delete;
+
+  std::string name_;
+  std::vector<std::unique_ptr<Variable>> params_;
+  type::Type* return_type_ = nullptr;
+  std::vector<std::unique_ptr<Statement>> body_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_FUNCTION_H_
diff --git a/src/ast/identifier_expression.cc b/src/ast/identifier_expression.cc
new file mode 100644
index 0000000..9fcf4c5
--- /dev/null
+++ b/src/ast/identifier_expression.cc
@@ -0,0 +1,55 @@
+// 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/ast/identifier_expression.h"
+
+namespace tint {
+namespace ast {
+
+IdentifierExpression::IdentifierExpression(const std::string& name)
+    : Expression(), name_({name}) {}
+
+IdentifierExpression::IdentifierExpression(const Source& source,
+                                           const std::string& name)
+    : Expression(source), name_({name}) {}
+
+IdentifierExpression::IdentifierExpression(std::vector<std::string> name)
+    : Expression(), name_(std::move(name)) {}
+
+IdentifierExpression::IdentifierExpression(const Source& source,
+                                           std::vector<std::string> name)
+    : Expression(source), name_(std::move(name)) {}
+
+IdentifierExpression::~IdentifierExpression() = default;
+
+bool IdentifierExpression::IsValid() const {
+  return name_.size() > 0 && name_[1].size() > 0;
+}
+
+void IdentifierExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Identifier{";
+  bool first = true;
+  for (const auto& name : name_) {
+    if (!first)
+      out << "::";
+
+    first = false;
+    out << name;
+  }
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/identifier_expression.h b/src/ast/identifier_expression.h
new file mode 100644
index 0000000..8efe83c
--- /dev/null
+++ b/src/ast/identifier_expression.h
@@ -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.
+
+#ifndef SRC_AST_IDENTIFIER_EXPRESSION_H_
+#define SRC_AST_IDENTIFIER_EXPRESSION_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+
+namespace tint {
+namespace ast {
+
+/// An identifier expression
+class IdentifierExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param name the name
+  explicit IdentifierExpression(const std::string& name);
+  /// Constructor
+  /// @param source the source
+  /// @param name the name
+  IdentifierExpression(const Source& source, const std::string& name);
+  /// Constructor
+  /// @param name the name
+  explicit IdentifierExpression(std::vector<std::string> name);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param name the name
+  IdentifierExpression(const Source& source, std::vector<std::string> name);
+  /// Move constructor
+  IdentifierExpression(IdentifierExpression&&) = default;
+  ~IdentifierExpression() override;
+
+  /// Sets the name
+  /// @param name the name
+  void set_name(std::vector<std::string> name) { name_ = std::move(name); }
+  /// @returns the name
+  std::vector<std::string> name() const { return name_; }
+
+  /// @returns true if this is an identifier expression
+  bool IsIdentifier() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  IdentifierExpression(const IdentifierExpression&) = delete;
+
+  std::vector<std::string> name_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_IDENTIFIER_EXPRESSION_H_
diff --git a/src/ast/if_statement.cc b/src/ast/if_statement.cc
new file mode 100644
index 0000000..364b828
--- /dev/null
+++ b/src/ast/if_statement.cc
@@ -0,0 +1,77 @@
+// 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/ast/if_statement.h"
+
+#include "src/ast/else_statement.h"
+
+namespace tint {
+namespace ast {
+
+IfStatement::IfStatement() : Statement() {}
+
+IfStatement::IfStatement(std::unique_ptr<Expression> condition,
+                         std::vector<std::unique_ptr<Statement>> body)
+    : Statement(), condition_(std::move(condition)), body_(std::move(body)) {}
+
+IfStatement::IfStatement(const Source& source,
+                         std::unique_ptr<Expression> condition,
+                         std::vector<std::unique_ptr<Statement>> body)
+    : Statement(source),
+      condition_(std::move(condition)),
+      body_(std::move(body)) {}
+
+IfStatement::~IfStatement() = default;
+
+bool IfStatement::IsValid() const {
+  if (condition_ == nullptr)
+    return false;
+
+  if (premerge_.size() > 0 && else_statements_.size() > 1)
+    return false;
+
+  return true;
+}
+
+void IfStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "If{" << std::endl;
+  condition_->to_str(out, indent + 2);
+  out << std::endl;
+  make_indent(out, indent + 2);
+  out << "{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}" << std::endl;
+
+  for (const auto& e : else_statements_)
+    e->to_str(out, indent + 2);
+
+  if (premerge_.size() > 0) {
+    make_indent(out, indent + 2);
+    out << "premerge{" << std::endl;
+
+    for (const auto& stmt : premerge_)
+      stmt->to_str(out, indent + 4);
+
+    make_indent(out, indent + 2);
+    out << "}" << std::endl;
+  }
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/if_statement.h b/src/ast/if_statement.h
new file mode 100644
index 0000000..f775f6e
--- /dev/null
+++ b/src/ast/if_statement.h
@@ -0,0 +1,109 @@
+// 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_AST_IF_STATEMENT_H_
+#define SRC_AST_IF_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// An if statement
+class IfStatement : public Statement {
+ public:
+  /// Constructor
+  IfStatement();
+  /// Constructor
+  /// @param condition the if condition
+  /// @param body the if body
+  IfStatement(std::unique_ptr<Expression> condition,
+              std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param source the source information
+  /// @param condition the if condition
+  /// @param body the if body
+  IfStatement(const Source& source,
+              std::unique_ptr<Expression> condition,
+              std::vector<std::unique_ptr<Statement>> body);
+  /// Move constructor
+  IfStatement(IfStatement&&) = default;
+  ~IfStatement() override;
+
+  /// Sets the condition for the if statement
+  /// @param condition the condition to set
+  void set_condition(std::unique_ptr<Expression> condition) {
+    condition_ = std::move(condition);
+  }
+  /// @returns the if condition or nullptr if none set
+  Expression* condition() const { return condition_.get(); }
+
+  /// Sets the if body
+  /// @param body the if body
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the if body
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// Sets the else statements
+  /// @param else_statements the else statements to set
+  void set_else_statements(
+      std::vector<std::unique_ptr<ElseStatement>> else_statements) {
+    else_statements_ = std::move(else_statements);
+  }
+  /// @returns the else statements
+  const std::vector<std::unique_ptr<ElseStatement>>& else_statements() const {
+    return else_statements_;
+  }
+
+  /// Sets the premerge statements
+  /// @param premerge the premerge statements
+  void set_premerge(std::vector<std::unique_ptr<Statement>> premerge) {
+    premerge_ = std::move(premerge);
+  }
+  /// @returns the premerge statements
+  const std::vector<std::unique_ptr<Statement>>& premerge() const {
+    return premerge_;
+  }
+
+  /// @returns true if this is a if statement
+  bool IsIf() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  IfStatement(const IfStatement&) = delete;
+
+  std::unique_ptr<Expression> condition_;
+  std::vector<std::unique_ptr<Statement>> body_;
+  std::vector<std::unique_ptr<ElseStatement>> else_statements_;
+  std::vector<std::unique_ptr<Statement>> premerge_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_IF_STATEMENT_H_
diff --git a/src/ast/import.cc b/src/ast/import.cc
new file mode 100644
index 0000000..aa7aff8
--- /dev/null
+++ b/src/ast/import.cc
@@ -0,0 +1,54 @@
+// 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/ast/import.h"
+
+namespace tint {
+namespace ast {
+
+Import::Import(const std::string& path, const std::string& name)
+    : Node(), path_(path), name_(name) {}
+
+Import::Import(const Source& source,
+               const std::string& path,
+               const std::string& name)
+    : Node(source), path_(path), name_(name) {}
+
+Import::~Import() = default;
+
+bool Import::IsValid() const {
+  if (path_.length() == 0) {
+    return false;
+  }
+
+  auto len = name_.length();
+  if (len == 0) {
+    return false;
+  }
+
+  // Verify the import name ends in a character, number or _
+  if (len > 2 && !std::isalnum(name_[len - 1]) && name_[len] != '_') {
+    return false;
+  }
+
+  return true;
+}
+
+void Import::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << R"(Import{")" + path_ + R"(" as )" + name_ + "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/import.h b/src/ast/import.h
new file mode 100644
index 0000000..cb67c25
--- /dev/null
+++ b/src/ast/import.h
@@ -0,0 +1,76 @@
+// 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_AST_IMPORT_H_
+#define SRC_AST_IMPORT_H_
+
+#include <ostream>
+#include <string>
+
+#include "src/ast/node.h"
+
+namespace tint {
+namespace ast {
+
+/// An import statement.
+class Import : public Node {
+ public:
+  /// Create a new empty import statement
+  Import() = default;
+  /// Create a new import statement
+  /// @param path The import path e.g. GLSL.std.430
+  /// @param name The import reference name e.g. std::
+  Import(const std::string& path, const std::string& name);
+  /// Create a new import statement
+  /// @param source The input source for the import statement
+  /// @param path The import path e.g. GLSL.std.430
+  /// @param name The import reference name e.g. std::
+  Import(const Source& source,
+         const std::string& path,
+         const std::string& name);
+  /// Move constructor
+  Import(Import&&) = default;
+
+  ~Import() override;
+
+  /// Sets the import path
+  /// @param path the path to set
+  void set_path(const std::string& path) { path_ = path; }
+  /// @returns the import path
+  const std::string& path() const { return path_; }
+  /// Sets the import name
+  /// @param name the name to set
+  void set_name(const std::string& name) { name_ = name; }
+  /// @returns the import name
+  const std::string& name() const { return name_; }
+
+  /// @returns true if the name and path are both present
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  Import(const Import&) = delete;
+
+  std::string path_;
+  std::string name_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_IMPORT_H_
diff --git a/src/ast/import_test.cc b/src/ast/import_test.cc
new file mode 100644
index 0000000..48f5a77
--- /dev/null
+++ b/src/ast/import_test.cc
@@ -0,0 +1,91 @@
+// 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/ast/import.h"
+
+#include <sstream>
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using ImportTest = testing::Test;
+
+TEST_F(ImportTest, Creation) {
+  Import i("GLSL.std.430", "std::glsl");
+
+  EXPECT_EQ(i.path(), "GLSL.std.430");
+  EXPECT_EQ(i.name(), "std::glsl");
+  EXPECT_EQ(i.line(), 0);
+  EXPECT_EQ(i.column(), 0);
+}
+
+TEST_F(ImportTest, CreationWithSource) {
+  Source s{27, 4};
+  Import i(s, "GLSL.std.430", "std::glsl");
+
+  EXPECT_EQ(i.path(), "GLSL.std.430");
+  EXPECT_EQ(i.name(), "std::glsl");
+  EXPECT_EQ(i.line(), 27);
+  EXPECT_EQ(i.column(), 4);
+}
+
+TEST_F(ImportTest, CreationEmpty) {
+  Source s{27, 4};
+  Import i;
+  i.set_source(s);
+  i.set_path("GLSL.std.430");
+  i.set_name("std::glsl");
+
+  EXPECT_EQ(i.path(), "GLSL.std.430");
+  EXPECT_EQ(i.name(), "std::glsl");
+  EXPECT_EQ(i.line(), 27);
+  EXPECT_EQ(i.column(), 4);
+}
+
+TEST_F(ImportTest, to_str) {
+  Import i{"GLSL.std.430", "std::glsl"};
+  std::ostringstream out;
+  i.to_str(out, 2);
+  EXPECT_EQ(out.str(), "  Import{\"GLSL.std.430\" as std::glsl}\n");
+}
+
+TEST_F(ImportTest, IsValid) {
+  Import i{"GLSL.std.430", "std::glsl"};
+  EXPECT_TRUE(i.IsValid());
+}
+
+TEST_F(ImportTest, IsValid_MissingPath) {
+  Import i{"", "std::glsl"};
+  EXPECT_FALSE(i.IsValid());
+}
+
+TEST_F(ImportTest, IsValid_MissingName) {
+  Import i{"GLSL.std.430", ""};
+  EXPECT_FALSE(i.IsValid());
+}
+
+TEST_F(ImportTest, IsValid_MissingBoth) {
+  Import i;
+  EXPECT_FALSE(i.IsValid());
+}
+
+TEST_F(ImportTest, IsValid_InvalidEndingCharacter) {
+  Import i{"GLSL.std.430", "std::glsl::"};
+  EXPECT_FALSE(i.IsValid());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/initializer_expression.cc b/src/ast/initializer_expression.cc
new file mode 100644
index 0000000..f28f3c3
--- /dev/null
+++ b/src/ast/initializer_expression.cc
@@ -0,0 +1,43 @@
+// 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/ast/initializer_expression.h"
+
+#include <assert.h>
+
+#include "src/ast/const_initializer_expression.h"
+#include "src/ast/type_initializer_expression.h"
+
+namespace tint {
+namespace ast {
+
+InitializerExpression::InitializerExpression() = default;
+
+InitializerExpression::~InitializerExpression() = default;
+
+InitializerExpression::InitializerExpression(const Source& source)
+    : Expression(source) {}
+
+ConstInitializerExpression* InitializerExpression::AsConstInitializer() {
+  assert(IsConstInitializer());
+  return static_cast<ConstInitializerExpression*>(this);
+}
+
+TypeInitializerExpression* InitializerExpression::AsTypeInitializer() {
+  assert(IsTypeInitializer());
+  return static_cast<TypeInitializerExpression*>(this);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/initializer_expression.h b/src/ast/initializer_expression.h
new file mode 100644
index 0000000..0067c20
--- /dev/null
+++ b/src/ast/initializer_expression.h
@@ -0,0 +1,60 @@
+// 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_AST_INITIALIZER_EXPRESSION_H_
+#define SRC_AST_INITIALIZER_EXPRESSION_H_
+
+#include "src/ast/expression.h"
+
+namespace tint {
+namespace ast {
+
+class ConstInitializerExpression;
+class TypeInitializerExpression;
+
+/// Base class for initializer style expressions
+class InitializerExpression : public Expression {
+ public:
+  ~InitializerExpression() override;
+
+  /// @returns true if this is an initializer expression
+  bool IsInitializer() const override { return true; }
+
+  /// @returns true if this is a constant initializer
+  virtual bool IsConstInitializer() const { return false; }
+  /// @returns true if this is a type initializer
+  virtual bool IsTypeInitializer() const { return false; }
+
+  /// @returns this as a const initializer expression
+  ConstInitializerExpression* AsConstInitializer();
+  /// @returns this as a type initializer expression
+  TypeInitializerExpression* AsTypeInitializer();
+
+ protected:
+  /// Constructor
+  InitializerExpression();
+  /// Constructor
+  /// @param source the initializer source
+  explicit InitializerExpression(const Source& source);
+  /// Move constructor
+  InitializerExpression(InitializerExpression&&) = default;
+
+ private:
+  InitializerExpression(const InitializerExpression&) = delete;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_INITIALIZER_EXPRESSION_H_
diff --git a/src/ast/int_literal.cc b/src/ast/int_literal.cc
new file mode 100644
index 0000000..99e476c
--- /dev/null
+++ b/src/ast/int_literal.cc
@@ -0,0 +1,29 @@
+// 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/ast/int_literal.h"
+
+namespace tint {
+namespace ast {
+
+IntLiteral::IntLiteral(int32_t value) : value_(value) {}
+
+IntLiteral::~IntLiteral() = default;
+
+std::string IntLiteral::to_str() const {
+  return std::to_string(value_);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/int_literal.h b/src/ast/int_literal.h
new file mode 100644
index 0000000..b96e3b9
--- /dev/null
+++ b/src/ast/int_literal.h
@@ -0,0 +1,49 @@
+// 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_AST_INT_LITERAL_H_
+#define SRC_AST_INT_LITERAL_H_
+
+#include <string>
+
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A int literal
+class IntLiteral : public Literal {
+ public:
+  /// Constructor
+  /// @param value the int literals value
+  explicit IntLiteral(int32_t value);
+  ~IntLiteral() override;
+
+  /// @returns true if this is a int literal
+  bool IsInt() const override { return true; }
+
+  /// @returns the int literal value
+  int32_t value() const { return value_; }
+
+  /// @returns the literal as a string
+  std::string to_str() const override;
+
+ private:
+  int32_t value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_INT_LITERAL_H_
diff --git a/src/ast/int_literal_test.cc b/src/ast/int_literal_test.cc
new file mode 100644
index 0000000..7b7fe86
--- /dev/null
+++ b/src/ast/int_literal_test.cc
@@ -0,0 +1,45 @@
+// 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/ast/int_literal.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using IntLiteralTest = testing::Test;
+
+TEST_F(IntLiteralTest, Value) {
+  IntLiteral i{47};
+  ASSERT_TRUE(i.IsInt());
+  EXPECT_EQ(i.value(), 47);
+}
+
+TEST_F(IntLiteralTest, Is) {
+  IntLiteral i{42};
+  EXPECT_FALSE(i.IsBool());
+  EXPECT_TRUE(i.IsInt());
+  EXPECT_FALSE(i.IsFloat());
+  EXPECT_FALSE(i.IsUint());
+}
+
+TEST_F(IntLiteralTest, ToStr) {
+  IntLiteral i{-42};
+
+  EXPECT_EQ(i.to_str(), "-42");
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/kill_statement.cc b/src/ast/kill_statement.cc
new file mode 100644
index 0000000..70581a7
--- /dev/null
+++ b/src/ast/kill_statement.cc
@@ -0,0 +1,36 @@
+// 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/ast/kill_statement.h"
+
+namespace tint {
+namespace ast {
+
+KillStatement::KillStatement() : Statement() {}
+
+KillStatement::KillStatement(const Source& source) : Statement(source) {}
+
+KillStatement::~KillStatement() = default;
+
+bool KillStatement::IsValid() const {
+  return true;
+}
+
+void KillStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Kill{}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/kill_statement.h b/src/ast/kill_statement.h
new file mode 100644
index 0000000..15bf061
--- /dev/null
+++ b/src/ast/kill_statement.h
@@ -0,0 +1,53 @@
+// 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_AST_KILL_STATEMENT_H_
+#define SRC_AST_KILL_STATEMENT_H_
+
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// A kill statement
+class KillStatement : public Statement {
+ public:
+  /// Constructor
+  KillStatement();
+  /// Constructor
+  /// @param source the initializer source
+  explicit KillStatement(const Source& source);
+  /// Move constructor
+  KillStatement(KillStatement&&) = default;
+  ~KillStatement() override;
+
+  /// @returns true if this is a kill statement
+  bool IsKill() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  KillStatement(const KillStatement&) = delete;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_KILL_STATEMENT_H_
diff --git a/src/ast/literal.cc b/src/ast/literal.cc
new file mode 100644
index 0000000..055d33d
--- /dev/null
+++ b/src/ast/literal.cc
@@ -0,0 +1,52 @@
+// 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/ast/literal.h"
+
+#include <assert.h>
+
+#include "src/ast/bool_literal.h"
+#include "src/ast/float_literal.h"
+#include "src/ast/int_literal.h"
+#include "src/ast/uint_literal.h"
+
+namespace tint {
+namespace ast {
+
+Literal::Literal() = default;
+
+Literal::~Literal() = default;
+
+BoolLiteral* Literal::AsBool() {
+  assert(IsBool());
+  return static_cast<BoolLiteral*>(this);
+}
+
+FloatLiteral* Literal::AsFloat() {
+  assert(IsFloat());
+  return static_cast<FloatLiteral*>(this);
+}
+
+IntLiteral* Literal::AsInt() {
+  assert(IsInt());
+  return static_cast<IntLiteral*>(this);
+}
+
+UintLiteral* Literal::AsUint() {
+  assert(IsUint());
+  return static_cast<UintLiteral*>(this);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/literal.h b/src/ast/literal.h
new file mode 100644
index 0000000..af8b831
--- /dev/null
+++ b/src/ast/literal.h
@@ -0,0 +1,62 @@
+// 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_AST_LITERAL_H_
+#define SRC_AST_LITERAL_H_
+
+#include <string>
+
+namespace tint {
+namespace ast {
+
+class BoolLiteral;
+class FloatLiteral;
+class IntLiteral;
+class UintLiteral;
+
+/// Base class for a literal value
+class Literal {
+ public:
+  virtual ~Literal();
+
+  /// @returns true if this is a bool literal
+  virtual bool IsBool() const { return false; }
+  /// @returns true if this is a float literal
+  virtual bool IsFloat() const { return false; }
+  /// @returns true if this is a signed int literal
+  virtual bool IsInt() const { return false; }
+  /// @returns true if this is a unsigned int literal
+  virtual bool IsUint() const { return false; }
+
+  /// @returns the literal as a boolean literal
+  BoolLiteral* AsBool();
+  /// @returns the literal as a float literal
+  FloatLiteral* AsFloat();
+  /// @returns the literal as a int literal
+  IntLiteral* AsInt();
+  /// @returns the literal as a unsigned int literal
+  UintLiteral* AsUint();
+
+  /// @returns the literal as a string
+  virtual std::string to_str() const = 0;
+
+ protected:
+  /// Constructor
+  Literal();
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_LITERAL_H_
diff --git a/src/ast/location_decoration.cc b/src/ast/location_decoration.cc
new file mode 100644
index 0000000..45bec56
--- /dev/null
+++ b/src/ast/location_decoration.cc
@@ -0,0 +1,29 @@
+// 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/ast/location_decoration.h"
+
+namespace tint {
+namespace ast {
+
+LocationDecoration::LocationDecoration(size_t val) : value_(val) {}
+
+LocationDecoration::~LocationDecoration() = default;
+
+void LocationDecoration::to_str(std::ostream& out) const {
+  out << "location " << value_;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/location_decoration.h b/src/ast/location_decoration.h
new file mode 100644
index 0000000..69b61dc
--- /dev/null
+++ b/src/ast/location_decoration.h
@@ -0,0 +1,50 @@
+// 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_AST_LOCATION_DECORATION_H_
+#define SRC_AST_LOCATION_DECORATION_H_
+
+#include <stddef.h>
+
+#include "src/ast/variable_decoration.h"
+
+namespace tint {
+namespace ast {
+
+/// A location decoration
+class LocationDecoration : public VariableDecoration {
+ public:
+  /// constructor
+  /// @param value the location value
+  explicit LocationDecoration(size_t value);
+  ~LocationDecoration() override;
+
+  /// @returns true if this is a location decoration
+  bool IsLocation() const override { return true; }
+
+  /// @returns the location value
+  size_t value() const { return value_; }
+
+  /// Outputs the decoration to the given stream
+  /// @param out the stream to output too
+  void to_str(std::ostream& out) const override;
+
+ private:
+  size_t value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_LOCATION_DECORATION_H_
diff --git a/src/ast/location_decoration_test.cc b/src/ast/location_decoration_test.cc
new file mode 100644
index 0000000..7858193
--- /dev/null
+++ b/src/ast/location_decoration_test.cc
@@ -0,0 +1,38 @@
+// 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/ast/location_decoration.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using LocationDecorationTest = testing::Test;
+
+TEST_F(LocationDecorationTest, Creation) {
+  LocationDecoration d{2};
+  EXPECT_EQ(2, d.value());
+}
+
+TEST_F(LocationDecorationTest, Is) {
+  LocationDecoration d{2};
+  EXPECT_FALSE(d.IsBinding());
+  EXPECT_FALSE(d.IsBuiltin());
+  EXPECT_TRUE(d.IsLocation());
+  EXPECT_FALSE(d.IsSet());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/loop_statement.cc b/src/ast/loop_statement.cc
new file mode 100644
index 0000000..b0e645b
--- /dev/null
+++ b/src/ast/loop_statement.cc
@@ -0,0 +1,58 @@
+// 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/ast/loop_statement.h"
+
+namespace tint {
+namespace ast {
+
+LoopStatement::LoopStatement(std::vector<std::unique_ptr<Statement>> body,
+                             std::vector<std::unique_ptr<Statement>> continuing)
+    : Statement(), body_(std::move(body)), continuing_(std::move(continuing)) {}
+
+LoopStatement::LoopStatement(const Source& source,
+                             std::vector<std::unique_ptr<Statement>> body,
+                             std::vector<std::unique_ptr<Statement>> continuing)
+    : Statement(source),
+      body_(std::move(body)),
+      continuing_(std::move(continuing)) {}
+
+LoopStatement::~LoopStatement() = default;
+
+bool LoopStatement::IsValid() const {
+  return true;
+}
+
+void LoopStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Loop{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 2);
+
+  make_indent(out, indent + 2);
+  out << "continuing {" << std::endl;
+
+  for (const auto& stmt : continuing_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}" << std::endl;
+
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/loop_statement.h b/src/ast/loop_statement.h
new file mode 100644
index 0000000..99acd96
--- /dev/null
+++ b/src/ast/loop_statement.h
@@ -0,0 +1,85 @@
+// 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_AST_LOOP_STATEMENT_H_
+#define SRC_AST_LOOP_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// A loop statement
+class LoopStatement : public Statement {
+ public:
+  /// Constructor
+  /// @param body the body statements
+  /// @param continuing the continuing statements
+  LoopStatement(std::vector<std::unique_ptr<Statement>> body,
+                std::vector<std::unique_ptr<Statement>> continuing);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param body the body statements
+  /// @param continuing the continuing statements
+  LoopStatement(const Source& source,
+                std::vector<std::unique_ptr<Statement>> body,
+                std::vector<std::unique_ptr<Statement>> continuing);
+  /// Move constructor
+  LoopStatement(LoopStatement&&) = default;
+  ~LoopStatement() override;
+
+  /// Sets the body statements
+  /// @param body the body statements
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the body statements
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// Sets the continuing statements
+  /// @param continuing the continuing statements
+  void set_continuing(std::vector<std::unique_ptr<Statement>> continuing) {
+    continuing_ = std::move(continuing);
+  }
+  /// @returns the continuing statements
+  const std::vector<std::unique_ptr<Statement>>& continuing() const {
+    return continuing_;
+  }
+
+  /// @returns true if this is a loop statement
+  bool IsLoop() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  LoopStatement(const LoopStatement&) = delete;
+
+  std::vector<std::unique_ptr<Statement>> body_;
+  std::vector<std::unique_ptr<Statement>> continuing_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_LOOP_STATEMENT_H_
diff --git a/src/ast/member_accessor_expression.cc b/src/ast/member_accessor_expression.cc
new file mode 100644
index 0000000..24f43ba
--- /dev/null
+++ b/src/ast/member_accessor_expression.cc
@@ -0,0 +1,49 @@
+// 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/ast/member_accessor_expression.h"
+
+namespace tint {
+namespace ast {
+
+MemberAccessorExpression::MemberAccessorExpression(
+    std::unique_ptr<Expression> structure,
+    std::unique_ptr<IdentifierExpression> member)
+    : Expression(), struct_(std::move(structure)), member_(std::move(member)) {}
+
+MemberAccessorExpression::MemberAccessorExpression(
+    const Source& source,
+    std::unique_ptr<Expression> structure,
+    std::unique_ptr<IdentifierExpression> member)
+    : Expression(source),
+      struct_(std::move(structure)),
+      member_(std::move(member)) {}
+
+MemberAccessorExpression::~MemberAccessorExpression() = default;
+
+bool MemberAccessorExpression::IsValid() const {
+  return struct_ != nullptr && member_ != nullptr;
+}
+
+void MemberAccessorExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "MemberAccessor{" << std::endl;
+  struct_->to_str(out, indent + 2);
+  member_->to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/member_accessor_expression.h b/src/ast/member_accessor_expression.h
new file mode 100644
index 0000000..ff24bad
--- /dev/null
+++ b/src/ast/member_accessor_expression.h
@@ -0,0 +1,85 @@
+// 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_AST_MEMBER_ACCESSOR_EXPRESSION_H_
+#define SRC_AST_MEMBER_ACCESSOR_EXPRESSION_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/identifier_expression.h"
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A member accessor expression
+class MemberAccessorExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param structure the structure
+  /// @param member the member
+  MemberAccessorExpression(std::unique_ptr<Expression> structure,
+                           std::unique_ptr<IdentifierExpression> member);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param structure the structure
+  /// @param member the member
+  MemberAccessorExpression(const Source& source,
+                           std::unique_ptr<Expression> structure,
+                           std::unique_ptr<IdentifierExpression> member);
+  /// Move constructor
+  MemberAccessorExpression(MemberAccessorExpression&&) = default;
+  ~MemberAccessorExpression() override;
+
+  /// Sets the structure
+  /// @param structure the structure
+  void set_structure(std::unique_ptr<Expression> structure) {
+    struct_ = std::move(structure);
+  }
+  /// @returns the structure
+  Expression* structure() const { return struct_.get(); }
+
+  /// Sets the member
+  /// @param member the member
+  void set_member(std::unique_ptr<IdentifierExpression> member) {
+    member_ = std::move(member);
+  }
+  /// @returns the member expression
+  IdentifierExpression* member() const { return member_.get(); }
+
+  /// @returns true if this is a member accessor expression
+  bool IsMemberAccessor() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  MemberAccessorExpression(const MemberAccessorExpression&) = delete;
+
+  std::unique_ptr<Expression> struct_;
+  std::unique_ptr<IdentifierExpression> member_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_MEMBER_ACCESSOR_EXPRESSION_H_
diff --git a/src/ast/module.cc b/src/ast/module.cc
new file mode 100644
index 0000000..e5c5015
--- /dev/null
+++ b/src/ast/module.cc
@@ -0,0 +1,61 @@
+// 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/ast/module.h"
+
+#include <sstream>
+
+namespace tint {
+namespace ast {
+
+const Import* Module::FindImportByName(const std::string& name) {
+  for (const auto& import : imports_) {
+    if (import->name() == name)
+      return import.get();
+  }
+  return nullptr;
+}
+
+bool Module::IsValid() const {
+  for (const auto& import : imports_) {
+    if (!import->IsValid())
+      return false;
+  }
+  return true;
+}
+
+std::string Module::to_str() const {
+  std::ostringstream out;
+
+  for (const auto& import : imports_) {
+    import->to_str(out, 0);
+  }
+  for (const auto& var : global_variables_) {
+    var->to_str(out, 0);
+  }
+  for (const auto& ep : entry_points_) {
+    ep->to_str(out, 0);
+  }
+  for (const auto& alias : alias_types_) {
+    out << alias->name() << " -> " << alias->type()->type_name() << std::endl;
+  }
+  for (const auto& func : functions_) {
+    func->to_str(out, 0);
+  }
+
+  return out.str();
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/module.h b/src/ast/module.h
new file mode 100644
index 0000000..e0d1a7e
--- /dev/null
+++ b/src/ast/module.h
@@ -0,0 +1,110 @@
+// 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_AST_MODULE_H_
+#define SRC_AST_MODULE_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/ast/entry_point.h"
+#include "src/ast/function.h"
+#include "src/ast/import.h"
+#include "src/ast/type/alias_type.h"
+#include "src/ast/variable.h"
+
+namespace tint {
+namespace ast {
+
+/// Represents all the source in a given program.
+class Module {
+ public:
+  Module() = default;
+  /// Move constructor
+  Module(Module&&) = default;
+  ~Module() = default;
+
+  /// Add the given import to the module
+  /// @param import The import to add.
+  void AddImport(std::unique_ptr<Import> import) {
+    imports_.push_back(std::move(import));
+  }
+  /// @returns the imports for this module
+  const std::vector<std::unique_ptr<Import>>& imports() { return imports_; }
+  /// Find the import of the given name
+  /// @param name The import name to search for
+  /// @returns the import with the given name if found, nullptr otherwise.
+  const Import* FindImportByName(const std::string& name);
+
+  /// Add a global variable to the module
+  /// @param var the variable to add
+  void AddGlobalVariable(std::unique_ptr<Variable> var) {
+    global_variables_.push_back(std::move(var));
+  }
+  /// @returns the global variables for the module
+  const std::vector<std::unique_ptr<Variable>>& global_variables() const {
+    return global_variables_;
+  }
+
+  /// Adds an entry point to the module
+  /// @param ep the entry point to add
+  void AddEntryPoint(std::unique_ptr<EntryPoint> ep) {
+    entry_points_.push_back(std::move(ep));
+  }
+  /// @returns the entry points in the module
+  const std::vector<std::unique_ptr<EntryPoint>>& entry_points() const {
+    return entry_points_;
+  }
+
+  /// Adds a type alias to the module
+  /// @param type the alias to add
+  void AddAliasType(type::AliasType* type) { alias_types_.push_back(type); }
+  /// @returns the alias types in the module
+  const std::vector<type::AliasType*>& alias_types() const {
+    return alias_types_;
+  }
+
+  /// Adds a function to the module
+  /// @param func the function
+  void AddFunction(std::unique_ptr<Function> func) {
+    functions_.push_back(std::move(func));
+  }
+  /// @returns the modules functions
+  const std::vector<std::unique_ptr<Function>>& functions() const {
+    return functions_;
+  }
+
+  /// @returns true if all required fields in the AST are present.
+  bool IsValid() const;
+
+  /// @returns a string representation of the module
+  std::string to_str() const;
+
+ private:
+  Module(const Module&) = delete;
+
+  std::vector<std::unique_ptr<Import>> imports_;
+  std::vector<std::unique_ptr<Variable>> global_variables_;
+  std::vector<std::unique_ptr<EntryPoint>> entry_points_;
+  // The alias types are owned by the type manager
+  std::vector<type::AliasType*> alias_types_;
+  std::vector<std::unique_ptr<Function>> functions_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_MODULE_H_
diff --git a/src/ast/module_test.cc b/src/ast/module_test.cc
new file mode 100644
index 0000000..2cf1626
--- /dev/null
+++ b/src/ast/module_test.cc
@@ -0,0 +1,78 @@
+// 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/ast/module.h"
+
+#include <utility>
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using ModuleTest = testing::Test;
+
+TEST_F(ModuleTest, Creation) {
+  Module m;
+
+  EXPECT_EQ(m.imports().size(), 0);
+}
+
+TEST_F(ModuleTest, Imports) {
+  Module m;
+
+  m.AddImport(std::make_unique<Import>("GLSL.std.430", "std::glsl"));
+  m.AddImport(std::make_unique<Import>("OpenCL.debug.100", "std::debug"));
+
+  EXPECT_EQ(2, m.imports().size());
+  EXPECT_EQ("std::glsl", m.imports()[0]->name());
+}
+
+TEST_F(ModuleTest, LookupImport) {
+  Module m;
+
+  auto i = std::make_unique<Import>("GLSL.std.430", "std::glsl");
+  m.AddImport(std::move(i));
+  m.AddImport(std::make_unique<Import>("OpenCL.debug.100", "std::debug"));
+
+  auto import = m.FindImportByName("std::glsl");
+  ASSERT_NE(nullptr, import);
+  EXPECT_EQ(import->path(), "GLSL.std.430");
+  EXPECT_EQ(import->name(), "std::glsl");
+}
+
+TEST_F(ModuleTest, LookupImportMissing) {
+  Module m;
+  EXPECT_EQ(nullptr, m.FindImportByName("Missing"));
+}
+
+TEST_F(ModuleTest, IsValid_Empty) {
+  Module m;
+  EXPECT_TRUE(m.IsValid());
+}
+
+TEST_F(ModuleTest, IsValid_InvalidImport) {
+  Module m;
+  m.AddImport(std::make_unique<Import>());
+  EXPECT_FALSE(m.IsValid());
+}
+
+TEST_F(ModuleTest, IsValid_ValidImport) {
+  Module m;
+  m.AddImport(std::make_unique<Import>("GLSL.std.430", "std::glsl"));
+  EXPECT_TRUE(m.IsValid());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/node.cc b/src/ast/node.cc
new file mode 100644
index 0000000..8870db0
--- /dev/null
+++ b/src/ast/node.cc
@@ -0,0 +1,40 @@
+// 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/ast/node.h"
+
+#include <sstream>
+
+namespace tint {
+namespace ast {
+
+Node::Node() = default;
+
+Node::Node(const Source& source) : source_(source) {}
+
+Node::~Node() = default;
+
+void Node::make_indent(std::ostream& out, size_t indent) const {
+  for (size_t i = 0; i < indent; ++i)
+    out << " ";
+}
+
+std::string Node::str() const {
+  std::ostringstream out;
+  to_str(out, 0);
+  return out.str();
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/node.h b/src/ast/node.h
new file mode 100644
index 0000000..97c3bcf
--- /dev/null
+++ b/src/ast/node.h
@@ -0,0 +1,77 @@
+// 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_AST_NODE_H_
+#define SRC_AST_NODE_H_
+
+#include <ostream>
+#include <string>
+
+#include "src/source.h"
+
+namespace tint {
+namespace ast {
+
+/// AST base class node
+class Node {
+ public:
+  virtual ~Node();
+
+  /// @returns the node source data
+  const Source& source() const { return source_; }
+  /// Sets the source data
+  /// @param source the source data
+  void set_source(const Source& source) { source_ = source; }
+
+  /// @returns the line the node was declared on
+  size_t line() const { return source_.line; }
+  /// @returns the column the node was declared on
+  size_t column() const { return source_.column; }
+
+  /// @returns true if the node is valid
+  virtual bool IsValid() const = 0;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  virtual void to_str(std::ostream& out, size_t indent) const = 0;
+
+  /// Convenience wrapper around the |to_str| method.
+  /// @returns the node as a string
+  std::string str() const;
+
+ protected:
+  /// Create a new node
+  Node();
+  /// Create a new node
+  /// @param source The input source for the node
+  explicit Node(const Source& source);
+  /// Move constructor
+  Node(Node&&) = default;
+
+  /// Writes indent into stream
+  /// @param out the stream to write to
+  /// @param indent the number of spaces to write
+  void make_indent(std::ostream& out, size_t indent) const;
+
+ private:
+  Node(const Node&) = delete;
+
+  Source source_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_NODE_H_
diff --git a/src/ast/nop_statement.cc b/src/ast/nop_statement.cc
new file mode 100644
index 0000000..b325bb3
--- /dev/null
+++ b/src/ast/nop_statement.cc
@@ -0,0 +1,36 @@
+// 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/ast/nop_statement.h"
+
+namespace tint {
+namespace ast {
+
+NopStatement::NopStatement() : Statement() {}
+
+NopStatement::NopStatement(const Source& source) : Statement(source) {}
+
+NopStatement::~NopStatement() = default;
+
+bool NopStatement::IsValid() const {
+  return true;
+}
+
+void NopStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Nop{}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/nop_statement.h b/src/ast/nop_statement.h
new file mode 100644
index 0000000..6585728
--- /dev/null
+++ b/src/ast/nop_statement.h
@@ -0,0 +1,53 @@
+// 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_AST_NOP_STATEMENT_H_
+#define SRC_AST_NOP_STATEMENT_H_
+
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// A nop statement
+class NopStatement : public Statement {
+ public:
+  /// Constructor
+  NopStatement();
+  /// Constructor
+  /// @param source the initializer source
+  explicit NopStatement(const Source& source);
+  /// Move constructor
+  NopStatement(NopStatement&&) = default;
+  ~NopStatement() override;
+
+  /// @returns true if this is a nop statement
+  bool IsNop() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  NopStatement(const NopStatement&) = delete;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_NOP_STATEMENT_H_
diff --git a/src/ast/pipeline_stage.cc b/src/ast/pipeline_stage.cc
new file mode 100644
index 0000000..ec2682b
--- /dev/null
+++ b/src/ast/pipeline_stage.cc
@@ -0,0 +1,43 @@
+// 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/ast/pipeline_stage.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, PipelineStage stage) {
+  switch (stage) {
+    case PipelineStage::kNone: {
+      out << "none";
+      break;
+    }
+    case PipelineStage::kVertex: {
+      out << "vertex";
+      break;
+    }
+    case PipelineStage::kFragment: {
+      out << "fragment";
+      break;
+    }
+    case PipelineStage::kCompute: {
+      out << "compute";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/pipeline_stage.h b/src/ast/pipeline_stage.h
new file mode 100644
index 0000000..3733c8c
--- /dev/null
+++ b/src/ast/pipeline_stage.h
@@ -0,0 +1,31 @@
+// 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_AST_PIPELINE_STAGE_H_
+#define SRC_AST_PIPELINE_STAGE_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The pipeline stage
+enum class PipelineStage { kNone = -1, kVertex, kFragment, kCompute };
+
+std::ostream& operator<<(std::ostream& out, PipelineStage stage);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_PIPELINE_STAGE_H_
diff --git a/src/ast/regardless_statement.cc b/src/ast/regardless_statement.cc
new file mode 100644
index 0000000..2ad7bb4
--- /dev/null
+++ b/src/ast/regardless_statement.cc
@@ -0,0 +1,58 @@
+// 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/ast/regardless_statement.h"
+
+namespace tint {
+namespace ast {
+
+RegardlessStatement::RegardlessStatement(
+    std::unique_ptr<Expression> condition,
+    std::vector<std::unique_ptr<Statement>> body)
+    : Statement(), condition_(std::move(condition)), body_(std::move(body)) {}
+
+RegardlessStatement::RegardlessStatement(
+    const Source& source,
+    std::unique_ptr<Expression> condition,
+    std::vector<std::unique_ptr<Statement>> body)
+    : Statement(source),
+      condition_(std::move(condition)),
+      body_(std::move(body)) {}
+
+RegardlessStatement::~RegardlessStatement() = default;
+
+bool RegardlessStatement::IsValid() const {
+  return condition_ != nullptr;
+}
+
+void RegardlessStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Regardless{" << std::endl;
+
+  condition_->to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}";
+
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/regardless_statement.h b/src/ast/regardless_statement.h
new file mode 100644
index 0000000..54e9c60
--- /dev/null
+++ b/src/ast/regardless_statement.h
@@ -0,0 +1,84 @@
+// 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_AST_REGARDLESS_STATEMENT_H_
+#define SRC_AST_REGARDLESS_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// A regardless statement
+class RegardlessStatement : public Statement {
+ public:
+  /// Constructor
+  /// @param condition the condition expression
+  /// @param body the body statements
+  RegardlessStatement(std::unique_ptr<Expression> condition,
+                      std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param condition the condition expression
+  /// @param body the body statements
+  RegardlessStatement(const Source& source,
+                      std::unique_ptr<Expression> condition,
+                      std::vector<std::unique_ptr<Statement>> body);
+  /// Move constructor
+  RegardlessStatement(RegardlessStatement&&) = default;
+  ~RegardlessStatement() override;
+
+  /// Sets the condition expression
+  /// @param condition the condition expression
+  void set_condition(std::unique_ptr<Expression> condition) {
+    condition_ = std::move(condition);
+  }
+  /// @returns the condition statements
+  Expression* condition() const { return condition_.get(); }
+
+  /// Sets the body statements
+  /// @param body the body statements
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the body statements
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// @returns true if this is an regardless statement
+  bool IsRegardless() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  RegardlessStatement(const RegardlessStatement&) = delete;
+
+  std::unique_ptr<Expression> condition_;
+  std::vector<std::unique_ptr<Statement>> body_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_REGARDLESS_STATEMENT_H_
diff --git a/src/ast/relational_expression.cc b/src/ast/relational_expression.cc
new file mode 100644
index 0000000..794df41
--- /dev/null
+++ b/src/ast/relational_expression.cc
@@ -0,0 +1,55 @@
+// 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/ast/relational_expression.h"
+
+namespace tint {
+namespace ast {
+
+RelationalExpression::RelationalExpression(Relation relation,
+                                           std::unique_ptr<Expression> lhs,
+                                           std::unique_ptr<Expression> rhs)
+    : Expression(),
+      relation_(relation),
+      lhs_(std::move(lhs)),
+      rhs_(std::move(rhs)) {}
+
+RelationalExpression::RelationalExpression(const Source& source,
+                                           Relation relation,
+                                           std::unique_ptr<Expression> lhs,
+                                           std::unique_ptr<Expression> rhs)
+    : Expression(source),
+      relation_(relation),
+      lhs_(std::move(lhs)),
+      rhs_(std::move(rhs)) {}
+
+RelationalExpression::~RelationalExpression() = default;
+
+bool RelationalExpression::IsValid() const {
+  return relation_ != Relation::kNone && lhs_ != nullptr && rhs_ != nullptr;
+}
+
+void RelationalExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << relation_ << "(" << std::endl;
+  lhs_->to_str(out, indent + 2);
+  out << std::endl;
+  rhs_->to_str(out, indent + 2);
+  out << std::endl;
+  make_indent(out, indent);
+  out << ")" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/relational_expression.h b/src/ast/relational_expression.h
new file mode 100644
index 0000000..1404353
--- /dev/null
+++ b/src/ast/relational_expression.h
@@ -0,0 +1,220 @@
+// 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_AST_RELATIONAL_EXPRESSION_H_
+#define SRC_AST_RELATIONAL_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// The relation type
+enum class Relation {
+  kNone = 0,
+  kAnd,
+  kOr,
+  kXor,
+  kLogicalAnd,
+  kLogicalOr,
+  kEqual,
+  kNotEqual,
+  kLessThan,
+  kGreaterThan,
+  kLessThanEqual,
+  kGreaterThanEqual,
+  kUnordGreaterThan,
+  kUnordGreaterThanEqual,
+  kUnordLessThan,
+  kUnordLessThanEqual,
+  kUnordEqual,
+  kUnordNotEqual,
+  kSignedGreaterThan,
+  kSignedGreaterThanEqual,
+  kSignedLessThan,
+  kSignedLessThanEqual,
+  kShiftLeft,
+  kShiftRight,
+  kShiftRightArith,
+  kAdd,
+  kSubtract,
+  kMultiply,
+  kDivide,
+  kModulo,
+};
+
+/// An xor expression
+class RelationalExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param relation the relation type
+  /// @param lhs the left side of the expression
+  /// @param rhs the right side of the expression
+  RelationalExpression(Relation relation,
+                       std::unique_ptr<Expression> lhs,
+                       std::unique_ptr<Expression> rhs);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param relation the relation type
+  /// @param lhs the left side of the expression
+  /// @param rhs the right side of the expression
+  RelationalExpression(const Source& source,
+                       Relation relation,
+                       std::unique_ptr<Expression> lhs,
+                       std::unique_ptr<Expression> rhs);
+  /// Move constructor
+  RelationalExpression(RelationalExpression&&) = default;
+  ~RelationalExpression() override;
+
+  /// Sets the relation type
+  /// @param relation the relation type
+  void set_relation(Relation relation) { relation_ = relation; }
+  /// @returns the relation
+  Relation relation() const { return relation_; }
+
+  /// Sets the left side of the expression
+  /// @param lhs the left side to set
+  void set_lhs(std::unique_ptr<Expression> lhs) { lhs_ = std::move(lhs); }
+  /// @returns the left side expression
+  Expression* lhs() const { return lhs_.get(); }
+
+  /// Sets the right side of the expression
+  /// @param rhs the right side to set
+  void set_rhs(std::unique_ptr<Expression> rhs) { rhs_ = std::move(rhs); }
+  /// @returns the right side expression
+  Expression* rhs() const { return rhs_.get(); }
+
+  /// @returns true if this is a relational expression
+  bool IsRelational() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  RelationalExpression(const RelationalExpression&) = delete;
+
+  Relation relation_ = Relation::kNone;
+  std::unique_ptr<Expression> lhs_;
+  std::unique_ptr<Expression> rhs_;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Relation relation) {
+  switch (relation) {
+    case Relation::kNone:
+      out << "none";
+      break;
+    case Relation::kAnd:
+      out << "and";
+      break;
+    case Relation::kOr:
+      out << "or";
+      break;
+    case Relation::kXor:
+      out << "xor";
+      break;
+    case Relation::kLogicalAnd:
+      out << "logical_and";
+      break;
+    case Relation::kLogicalOr:
+      out << "logical_or";
+      break;
+    case Relation::kEqual:
+      out << "equal";
+      break;
+    case Relation::kNotEqual:
+      out << "not_equal";
+      break;
+    case Relation::kLessThan:
+      out << "less_than";
+      break;
+    case Relation::kGreaterThan:
+      out << "greater_than";
+      break;
+    case Relation::kLessThanEqual:
+      out << "less_than_equal";
+      break;
+    case Relation::kGreaterThanEqual:
+      out << "greater_than_equal";
+      break;
+    case Relation::kUnordGreaterThan:
+      out << "unord_greater_than";
+      break;
+    case Relation::kUnordGreaterThanEqual:
+      out << "unord_greater_than_equal";
+      break;
+    case Relation::kUnordLessThan:
+      out << "unord_less_than";
+      break;
+    case Relation::kUnordLessThanEqual:
+      out << "unord_less_than_equal";
+      break;
+    case Relation::kUnordEqual:
+      out << "unord_equal";
+      break;
+    case Relation::kUnordNotEqual:
+      out << "unord_not_equal";
+      break;
+    case Relation::kSignedGreaterThan:
+      out << "signed_greateR_than";
+      break;
+    case Relation::kSignedGreaterThanEqual:
+      out << "signed_greater_than_equal";
+      break;
+    case Relation::kSignedLessThan:
+      out << "signed_less_than";
+      break;
+    case Relation::kSignedLessThanEqual:
+      out << "signed_less_than_equal";
+      break;
+    case Relation::kShiftLeft:
+      out << "shift_left";
+      break;
+    case Relation::kShiftRight:
+      out << "shift_right";
+      break;
+    case Relation::kShiftRightArith:
+      out << "shift_right_arith";
+      break;
+    case Relation::kAdd:
+      out << "add";
+      break;
+    case Relation::kSubtract:
+      out << "subtract";
+      break;
+    case Relation::kMultiply:
+      out << "multiply";
+      break;
+    case Relation::kDivide:
+      out << "divide";
+      break;
+    case Relation::kModulo:
+      out << "modulo";
+      break;
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_RELATIONAL_EXPRESSION_H_
diff --git a/src/ast/return_statement.cc b/src/ast/return_statement.cc
new file mode 100644
index 0000000..5a6dcc2
--- /dev/null
+++ b/src/ast/return_statement.cc
@@ -0,0 +1,48 @@
+// 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/ast/return_statement.h"
+
+namespace tint {
+namespace ast {
+
+ReturnStatement::ReturnStatement() : Statement() {}
+
+ReturnStatement::ReturnStatement(std::unique_ptr<Expression> value)
+    : Statement(), value_(std::move(value)) {}
+
+ReturnStatement::ReturnStatement(const Source& source,
+                                 std::unique_ptr<Expression> value)
+    : Statement(source), value_(std::move(value)) {}
+
+ReturnStatement::~ReturnStatement() = default;
+
+bool ReturnStatement::IsValid() const {
+  return true;
+}
+
+void ReturnStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Return{";
+
+  if (value_) {
+    out << std::endl;
+    value_->to_str(out, indent);
+    make_indent(out, indent);
+  }
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/return_statement.h b/src/ast/return_statement.h
new file mode 100644
index 0000000..30ada9c
--- /dev/null
+++ b/src/ast/return_statement.h
@@ -0,0 +1,71 @@
+// 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_AST_RETURN_STATEMENT_H_
+#define SRC_AST_RETURN_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// A return statement
+class ReturnStatement : public Statement {
+ public:
+  /// Constructor
+  ReturnStatement();
+  /// Constructor
+  /// @param value the return value
+  explicit ReturnStatement(std::unique_ptr<Expression> value);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param value the return value
+  ReturnStatement(const Source& source, std::unique_ptr<Expression> value);
+  /// Move constructor
+  ReturnStatement(ReturnStatement&&) = default;
+  ~ReturnStatement() override;
+
+  /// Sets the value
+  /// @param value the value
+  void set_value(std::unique_ptr<Expression> value) {
+    value_ = std::move(value);
+  }
+  /// @returns the value
+  Expression* value() const { return value_.get(); }
+
+  /// @returns true if this is a return statement
+  bool IsReturn() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  ReturnStatement(const ReturnStatement&) = delete;
+
+  std::unique_ptr<Expression> value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_RETURN_STATEMENT_H_
diff --git a/src/ast/set_decoration.cc b/src/ast/set_decoration.cc
new file mode 100644
index 0000000..c27ee26
--- /dev/null
+++ b/src/ast/set_decoration.cc
@@ -0,0 +1,29 @@
+// 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/ast/set_decoration.h"
+
+namespace tint {
+namespace ast {
+
+SetDecoration::SetDecoration(size_t val) : value_(val) {}
+
+SetDecoration::~SetDecoration() = default;
+
+void SetDecoration::to_str(std::ostream& out) const {
+  out << "set " << value_;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/set_decoration.h b/src/ast/set_decoration.h
new file mode 100644
index 0000000..253e940
--- /dev/null
+++ b/src/ast/set_decoration.h
@@ -0,0 +1,50 @@
+// 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_AST_SET_DECORATION_H_
+#define SRC_AST_SET_DECORATION_H_
+
+#include <stddef.h>
+
+#include "src/ast/variable_decoration.h"
+
+namespace tint {
+namespace ast {
+
+/// A set decoration
+class SetDecoration : public VariableDecoration {
+ public:
+  /// constructor
+  /// @param value the set value
+  explicit SetDecoration(size_t value);
+  ~SetDecoration() override;
+
+  /// @returns true if this is a set decoration
+  bool IsSet() const override { return true; }
+
+  /// @returns the set value
+  size_t value() const { return value_; }
+
+  /// Outputs the decoration to the given stream
+  /// @param out the stream to output too
+  void to_str(std::ostream& out) const override;
+
+ private:
+  size_t value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_SET_DECORATION_H_
diff --git a/src/ast/set_decoration_test.cc b/src/ast/set_decoration_test.cc
new file mode 100644
index 0000000..8295e1f
--- /dev/null
+++ b/src/ast/set_decoration_test.cc
@@ -0,0 +1,38 @@
+// 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/ast/set_decoration.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using SetDecorationTest = testing::Test;
+
+TEST_F(SetDecorationTest, Creation) {
+  SetDecoration d{2};
+  EXPECT_EQ(2, d.value());
+}
+
+TEST_F(SetDecorationTest, Is) {
+  SetDecoration d{2};
+  EXPECT_FALSE(d.IsBinding());
+  EXPECT_FALSE(d.IsBuiltin());
+  EXPECT_FALSE(d.IsLocation());
+  EXPECT_TRUE(d.IsSet());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/statement.cc b/src/ast/statement.cc
new file mode 100644
index 0000000..07a1f09
--- /dev/null
+++ b/src/ast/statement.cc
@@ -0,0 +1,120 @@
+// 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/ast/statement.h"
+
+#include <assert.h>
+
+#include "src/ast/assignment_statement.h"
+#include "src/ast/break_statement.h"
+#include "src/ast/case_statement.h"
+#include "src/ast/continue_statement.h"
+#include "src/ast/else_statement.h"
+#include "src/ast/fallthrough_statement.h"
+#include "src/ast/if_statement.h"
+#include "src/ast/kill_statement.h"
+#include "src/ast/loop_statement.h"
+#include "src/ast/nop_statement.h"
+#include "src/ast/regardless_statement.h"
+#include "src/ast/return_statement.h"
+#include "src/ast/switch_statement.h"
+#include "src/ast/unless_statement.h"
+#include "src/ast/variable_statement.h"
+
+namespace tint {
+namespace ast {
+
+Statement::Statement() = default;
+
+Statement::Statement(const Source& source) : Node(source) {}
+
+Statement::~Statement() = default;
+
+AssignmentStatement* Statement::AsAssign() {
+  assert(IsAssign());
+  return static_cast<AssignmentStatement*>(this);
+}
+
+BreakStatement* Statement::AsBreak() {
+  assert(IsBreak());
+  return static_cast<BreakStatement*>(this);
+}
+
+CaseStatement* Statement::AsCase() {
+  assert(IsCase());
+  return static_cast<CaseStatement*>(this);
+}
+
+ContinueStatement* Statement::AsContinue() {
+  assert(IsContinue());
+  return static_cast<ContinueStatement*>(this);
+}
+
+ElseStatement* Statement::AsElse() {
+  assert(IsElse());
+  return static_cast<ElseStatement*>(this);
+}
+
+FallthroughStatement* Statement::AsFallthrough() {
+  assert(IsFallthrough());
+  return static_cast<FallthroughStatement*>(this);
+}
+
+IfStatement* Statement::AsIf() {
+  assert(IsIf());
+  return static_cast<IfStatement*>(this);
+}
+
+KillStatement* Statement::AsKill() {
+  assert(IsKill());
+  return static_cast<KillStatement*>(this);
+}
+
+LoopStatement* Statement::AsLoop() {
+  assert(IsLoop());
+  return static_cast<LoopStatement*>(this);
+}
+
+NopStatement* Statement::AsNop() {
+  assert(IsNop());
+  return static_cast<NopStatement*>(this);
+}
+
+RegardlessStatement* Statement::AsRegardless() {
+  assert(IsRegardless());
+  return static_cast<RegardlessStatement*>(this);
+}
+
+ReturnStatement* Statement::AsReturn() {
+  assert(IsReturn());
+  return static_cast<ReturnStatement*>(this);
+}
+
+SwitchStatement* Statement::AsSwitch() {
+  assert(IsSwitch());
+  return static_cast<SwitchStatement*>(this);
+}
+
+UnlessStatement* Statement::AsUnless() {
+  assert(IsUnless());
+  return static_cast<UnlessStatement*>(this);
+}
+
+VariableStatement* Statement::AsVariable() {
+  assert(IsVariable());
+  return static_cast<VariableStatement*>(this);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/statement.h b/src/ast/statement.h
new file mode 100644
index 0000000..112f580
--- /dev/null
+++ b/src/ast/statement.h
@@ -0,0 +1,122 @@
+// 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_AST_STATEMENT_H_
+#define SRC_AST_STATEMENT_H_
+
+#include "src/ast/node.h"
+
+namespace tint {
+namespace ast {
+
+class AssignmentStatement;
+class BreakStatement;
+class CaseStatement;
+class ContinueStatement;
+class ElseStatement;
+class FallthroughStatement;
+class IfStatement;
+class KillStatement;
+class LoopStatement;
+class NopStatement;
+class RegardlessStatement;
+class ReturnStatement;
+class SwitchStatement;
+class UnlessStatement;
+class VariableStatement;
+
+/// Base statement class
+class Statement : public Node {
+ public:
+  ~Statement() override;
+
+  /// @returns true if this is an assign statement
+  virtual bool IsAssign() const { return false; }
+  /// @returns true if this is a break statement
+  virtual bool IsBreak() const { return false; }
+  /// @returns true if this is a case statement
+  virtual bool IsCase() const { return false; }
+  /// @returns true if this is a continue statement
+  virtual bool IsContinue() const { return false; }
+  /// @returns true if this is an else statement
+  virtual bool IsElse() const { return false; }
+  /// @returns true if this is a fallthrough statement
+  virtual bool IsFallthrough() const { return false; }
+  /// @returns true if this is an if statement
+  virtual bool IsIf() const { return false; }
+  /// @returns true if this is a kill statement
+  virtual bool IsKill() const { return false; }
+  /// @returns true if this is a loop statement
+  virtual bool IsLoop() const { return false; }
+  /// @returns true if this is a nop statement
+  virtual bool IsNop() const { return false; }
+  /// @returns true if this is an regardless statement
+  virtual bool IsRegardless() const { return false; }
+  /// @returns true if this is a return statement
+  virtual bool IsReturn() const { return false; }
+  /// @returns true if this is a switch statement
+  virtual bool IsSwitch() const { return false; }
+  /// @returns true if this is an unless statement
+  virtual bool IsUnless() const { return false; }
+  /// @returns true if this is an variable statement
+  virtual bool IsVariable() const { return false; }
+
+  /// @returns the statement as an assign statement
+  AssignmentStatement* AsAssign();
+  /// @returns the statement as a break statement
+  BreakStatement* AsBreak();
+  /// @returns the statement as a case statement
+  CaseStatement* AsCase();
+  /// @returns the statement as a continue statement
+  ContinueStatement* AsContinue();
+  /// @returns the statement as a else statement
+  ElseStatement* AsElse();
+  /// @returns the statement as a fallthrough statement
+  FallthroughStatement* AsFallthrough();
+  /// @returns the statement as a if statement
+  IfStatement* AsIf();
+  /// @returns the statement as a kill statement
+  KillStatement* AsKill();
+  /// @returns the statement as a loop statement
+  LoopStatement* AsLoop();
+  /// @returns the statement as a nop statement
+  NopStatement* AsNop();
+  /// @returns the statement as an regardless statement
+  RegardlessStatement* AsRegardless();
+  /// @returns the statement as a return statement
+  ReturnStatement* AsReturn();
+  /// @returns the statement as a switch statement
+  SwitchStatement* AsSwitch();
+  /// @returns the statement as an unless statement
+  UnlessStatement* AsUnless();
+  /// @returns the statement as an variable statement
+  VariableStatement* AsVariable();
+
+ protected:
+  /// Constructor
+  Statement();
+  /// Constructor
+  /// @param source the source of the expression
+  explicit Statement(const Source& source);
+  /// Move constructor
+  Statement(Statement&&) = default;
+
+ private:
+  Statement(const Statement&) = delete;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STATEMENT_H_
diff --git a/src/ast/statement_condition.cc b/src/ast/statement_condition.cc
new file mode 100644
index 0000000..dc2136f
--- /dev/null
+++ b/src/ast/statement_condition.cc
@@ -0,0 +1,37 @@
+// 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/ast/statement_condition.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, StatementCondition condition) {
+  switch (condition) {
+    case StatementCondition::kNone:
+      out << "none";
+      break;
+    case StatementCondition::kIf:
+      out << "if";
+      break;
+    case StatementCondition::kUnless:
+      out << "unless";
+      break;
+  }
+
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/statement_condition.h b/src/ast/statement_condition.h
new file mode 100644
index 0000000..fa4149e
--- /dev/null
+++ b/src/ast/statement_condition.h
@@ -0,0 +1,31 @@
+// 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_AST_STATEMENT_CONDITION_H_
+#define SRC_AST_STATEMENT_CONDITION_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// Type of  condition attached to a statement
+enum class StatementCondition { kNone = 0, kIf, kUnless };
+
+std::ostream& operator<<(std::ostream& out, StatementCondition condition);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STATEMENT_CONDITION_H_
diff --git a/src/ast/storage_class.cc b/src/ast/storage_class.cc
new file mode 100644
index 0000000..e0c71f7
--- /dev/null
+++ b/src/ast/storage_class.cc
@@ -0,0 +1,71 @@
+// 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/ast/storage_class.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, StorageClass sc) {
+  switch (sc) {
+    case StorageClass::kNone: {
+      out << "none";
+      break;
+    }
+    case StorageClass::kInput: {
+      out << "input";
+      break;
+    }
+    case StorageClass::kOutput: {
+      out << "output";
+      break;
+    }
+    case StorageClass::kUniform: {
+      out << "uniform";
+      break;
+    }
+    case StorageClass::kWorkgroup: {
+      out << "workgroup";
+      break;
+    }
+    case StorageClass::kUniformConstant: {
+      out << "uniform_constant";
+      break;
+    }
+    case StorageClass::kStorageBuffer: {
+      out << "storage_buffer";
+      break;
+    }
+    case StorageClass::kImage: {
+      out << "image";
+      break;
+    }
+    case StorageClass::kPushConstant: {
+      out << "push_constant";
+      break;
+    }
+    case StorageClass::kPrivate: {
+      out << "private";
+      break;
+    }
+    case StorageClass::kFunction: {
+      out << "function";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/storage_class.h b/src/ast/storage_class.h
new file mode 100644
index 0000000..3a25fed
--- /dev/null
+++ b/src/ast/storage_class.h
@@ -0,0 +1,43 @@
+// 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_AST_STORAGE_CLASS_H_
+#define SRC_AST_STORAGE_CLASS_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// Storage class of a given pointer.
+enum class StorageClass {
+  kNone = -1,
+  kInput,
+  kOutput,
+  kUniform,
+  kWorkgroup,
+  kUniformConstant,
+  kStorageBuffer,
+  kImage,
+  kPushConstant,
+  kPrivate,
+  kFunction
+};
+
+std::ostream& operator<<(std::ostream& out, StorageClass sc);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STORAGE_CLASS_H_
diff --git a/src/ast/struct.cc b/src/ast/struct.cc
new file mode 100644
index 0000000..1cdf866
--- /dev/null
+++ b/src/ast/struct.cc
@@ -0,0 +1,49 @@
+// 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/ast/struct.h"
+
+namespace tint {
+namespace ast {
+
+Struct::Struct(StructDecoration decoration,
+               std::vector<std::unique_ptr<StructMember>> members)
+    : Node(), decoration_(decoration), members_(std::move(members)) {}
+
+Struct::Struct(const Source& source,
+               StructDecoration decoration,
+               std::vector<std::unique_ptr<StructMember>> members)
+    : Node(source), decoration_(decoration), members_(std::move(members)) {}
+
+Struct::~Struct() = default;
+
+bool Struct::IsValid() const {
+  return true;
+}
+
+void Struct::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  if (decoration_ != StructDecoration::kNone) {
+    out << "[[" << decoration_ << "]] ";
+  }
+  out << "Struct{" << std::endl;
+  for (const auto& member : members_) {
+    member->to_str(out, indent + 2);
+  }
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct.h b/src/ast/struct.h
new file mode 100644
index 0000000..a3d2e12
--- /dev/null
+++ b/src/ast/struct.h
@@ -0,0 +1,87 @@
+// 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_AST_STRUCT_H_
+#define SRC_AST_STRUCT_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/ast/node.h"
+#include "src/ast/struct_decoration.h"
+#include "src/ast/struct_member.h"
+
+namespace tint {
+namespace ast {
+
+/// A struct statement.
+class Struct : public Node {
+ public:
+  /// Create a new empty struct statement
+  Struct() = default;
+  /// Create a new struct statement
+  /// @param decoration The struct decorations
+  /// @param members The struct members
+  Struct(StructDecoration decoration,
+         std::vector<std::unique_ptr<StructMember>> members);
+  /// Create a new struct statement
+  /// @param source The input source for the import statement
+  /// @param decoration The struct decorations
+  /// @param members The struct members
+  Struct(const Source& source,
+         StructDecoration decoration,
+         std::vector<std::unique_ptr<StructMember>> members);
+  /// Move constructor
+  Struct(Struct&&) = default;
+
+  ~Struct() override;
+
+  /// Sets the struct decoration
+  /// @param deco the decoration to set
+  void set_decoration(StructDecoration deco) { decoration_ = deco; }
+  /// @returns the struct decoration
+  StructDecoration decoration() const { return decoration_; }
+
+  /// Sets the struct members
+  /// @param members the members to set
+  void set_members(std::vector<std::unique_ptr<StructMember>> members) {
+    members_ = std::move(members);
+  }
+  /// @returns the members
+  const std::vector<std::unique_ptr<StructMember>>& members() const {
+    return members_;
+  }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  Struct(const Struct&) = delete;
+
+  StructDecoration decoration_ = StructDecoration::kNone;
+  std::vector<std::unique_ptr<StructMember>> members_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STRUCT_H_
diff --git a/src/ast/struct_decoration.cc b/src/ast/struct_decoration.cc
new file mode 100644
index 0000000..10ee485
--- /dev/null
+++ b/src/ast/struct_decoration.cc
@@ -0,0 +1,35 @@
+// 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/ast/struct_decoration.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, StructDecoration stage) {
+  switch (stage) {
+    case StructDecoration::kNone: {
+      out << "none";
+      break;
+    }
+    case StructDecoration::kBlock: {
+      out << "block";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct_decoration.h b/src/ast/struct_decoration.h
new file mode 100644
index 0000000..fab582c
--- /dev/null
+++ b/src/ast/struct_decoration.h
@@ -0,0 +1,31 @@
+// 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_AST_STRUCT_DECORATION_H_
+#define SRC_AST_STRUCT_DECORATION_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The struct decorations
+enum class StructDecoration { kNone = -1, kBlock };
+
+std::ostream& operator<<(std::ostream& out, StructDecoration stage);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STRUCT_DECORATION_H_
diff --git a/src/ast/struct_member.cc b/src/ast/struct_member.cc
new file mode 100644
index 0000000..4ad5230
--- /dev/null
+++ b/src/ast/struct_member.cc
@@ -0,0 +1,62 @@
+// 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/ast/struct_member.h"
+
+namespace tint {
+namespace ast {
+
+StructMember::StructMember(
+    const std::string& name,
+    type::Type* type,
+    std::vector<std::unique_ptr<StructMemberDecoration>> decorations)
+    : Node(), name_(name), type_(type), decorations_(std::move(decorations)) {}
+
+StructMember::StructMember(
+    const Source& source,
+    const std::string& name,
+    type::Type* type,
+    std::vector<std::unique_ptr<StructMemberDecoration>> decorations)
+    : Node(source),
+      name_(name),
+      type_(type),
+      decorations_(std::move(decorations)) {}
+
+StructMember::~StructMember() = default;
+
+bool StructMember::IsValid() const {
+  if (name_.length() == 0) {
+    return false;
+  }
+  if (type_ == nullptr) {
+    return false;
+  }
+  return true;
+}
+
+void StructMember::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "StructMember{";
+  if (decorations_.size() > 0) {
+    out << "[[ ";
+    for (const auto& deco : decorations_)
+      out << deco->to_str() << " ";
+    out << "]] ";
+  }
+
+  out << name_ << ": " << type_->type_name() << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct_member.h b/src/ast/struct_member.h
new file mode 100644
index 0000000..0aceb81
--- /dev/null
+++ b/src/ast/struct_member.h
@@ -0,0 +1,100 @@
+// 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_AST_STRUCT_MEMBER_H_
+#define SRC_AST_STRUCT_MEMBER_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "src/ast/node.h"
+#include "src/ast/struct_member_decoration.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+
+/// A struct member statement.
+class StructMember : public Node {
+ public:
+  /// Create a new empty struct member statement
+  StructMember() = default;
+  /// Create a new struct member statement
+  /// @param name The struct member name
+  /// @param type The struct member type
+  /// @param decorations The struct member decorations
+  StructMember(
+      const std::string& name,
+      type::Type* type,
+      std::vector<std::unique_ptr<StructMemberDecoration>> decorations);
+  /// Create a new struct member statement
+  /// @param source The input source for the struct member statement
+  /// @param name The struct member name
+  /// @param type The struct member type
+  /// @param decorations The struct member decorations
+  StructMember(
+      const Source& source,
+      const std::string& name,
+      type::Type* type,
+      std::vector<std::unique_ptr<StructMemberDecoration>> decorations);
+  /// Move constructor
+  StructMember(StructMember&&) = default;
+
+  ~StructMember() override;
+
+  /// Sets the name
+  /// @param name the name to set
+  void set_name(const std::string& name) { name_ = name; }
+  /// @returns the name
+  const std::string& name() const { return name_; }
+  /// Sets the type
+  /// @param type the type to set
+  void set_type(type::Type* type) { type_ = type; }
+  /// @returns the type
+  type::Type* type() const { return type_; }
+  /// Sets the decorations
+  /// @param decorations the decorations
+  void set_decorations(
+      std::vector<std::unique_ptr<StructMemberDecoration>> decorations) {
+    decorations_ = std::move(decorations);
+  }
+  /// @returns the decorations
+  const std::vector<std::unique_ptr<StructMemberDecoration>>& decorations()
+      const {
+    return decorations_;
+  }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  StructMember(const StructMember&) = delete;
+
+  std::string name_;
+  type::Type* type_ = nullptr;
+  std::vector<std::unique_ptr<StructMemberDecoration>> decorations_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STRUCT_MEMBER_H_
diff --git a/src/ast/struct_member_decoration.cc b/src/ast/struct_member_decoration.cc
new file mode 100644
index 0000000..bcb091a
--- /dev/null
+++ b/src/ast/struct_member_decoration.cc
@@ -0,0 +1,34 @@
+// 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/ast/struct_member_decoration.h"
+
+#include <assert.h>
+
+#include "src/ast/struct_member_offset_decoration.h"
+
+namespace tint {
+namespace ast {
+
+StructMemberDecoration::StructMemberDecoration() = default;
+
+StructMemberDecoration::~StructMemberDecoration() = default;
+
+StructMemberOffsetDecoration* StructMemberDecoration::AsOffset() {
+  assert(IsOffset());
+  return static_cast<StructMemberOffsetDecoration*>(this);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct_member_decoration.h b/src/ast/struct_member_decoration.h
new file mode 100644
index 0000000..525bb64
--- /dev/null
+++ b/src/ast/struct_member_decoration.h
@@ -0,0 +1,46 @@
+// 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_AST_STRUCT_MEMBER_DECORATION_H_
+#define SRC_AST_STRUCT_MEMBER_DECORATION_H_
+
+#include <string>
+
+namespace tint {
+namespace ast {
+
+class StructMemberOffsetDecoration;
+
+/// A decoration attached to a struct member
+class StructMemberDecoration {
+ public:
+  virtual ~StructMemberDecoration();
+
+  /// @returns true if this is an offset decoration
+  virtual bool IsOffset() const { return false; }
+
+  /// @returns the decoration as an offset decoration
+  StructMemberOffsetDecoration* AsOffset();
+
+  /// @returns the decoration as a string
+  virtual std::string to_str() const = 0;
+
+ protected:
+  StructMemberDecoration();
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STRUCT_MEMBER_DECORATION_H_
diff --git a/src/ast/struct_member_offset_decoration.cc b/src/ast/struct_member_offset_decoration.cc
new file mode 100644
index 0000000..0a70a95
--- /dev/null
+++ b/src/ast/struct_member_offset_decoration.cc
@@ -0,0 +1,30 @@
+// 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/ast/struct_member_offset_decoration.h"
+
+namespace tint {
+namespace ast {
+
+StructMemberOffsetDecoration::StructMemberOffsetDecoration(size_t offset)
+    : offset_(offset) {}
+
+StructMemberOffsetDecoration::~StructMemberOffsetDecoration() = default;
+
+std::string StructMemberOffsetDecoration::to_str() const {
+  return "offset " + std::to_string(offset_);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct_member_offset_decoration.h b/src/ast/struct_member_offset_decoration.h
new file mode 100644
index 0000000..8e15a63
--- /dev/null
+++ b/src/ast/struct_member_offset_decoration.h
@@ -0,0 +1,51 @@
+// 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_AST_STRUCT_MEMBER_OFFSET_DECORATION_H_
+#define SRC_AST_STRUCT_MEMBER_OFFSET_DECORATION_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "src/ast/struct_member_decoration.h"
+
+namespace tint {
+namespace ast {
+
+/// A struct member offset decoration
+class StructMemberOffsetDecoration : public StructMemberDecoration {
+ public:
+  /// constructor
+  /// @param offset the offset value
+  explicit StructMemberOffsetDecoration(size_t offset);
+  ~StructMemberOffsetDecoration() override;
+
+  /// @returns true if this is an offset decoration
+  bool IsOffset() const override { return true; }
+
+  /// @returns the offset value
+  size_t offset() const { return offset_; }
+
+  /// @returns the decoration as a string
+  std::string to_str() const override;
+
+ private:
+  size_t offset_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_STRUCT_MEMBER_OFFSET_DECORATION_H_
diff --git a/src/ast/struct_member_offset_decoration_test.cc b/src/ast/struct_member_offset_decoration_test.cc
new file mode 100644
index 0000000..cd2e2b9
--- /dev/null
+++ b/src/ast/struct_member_offset_decoration_test.cc
@@ -0,0 +1,35 @@
+// 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/ast/struct_member_offset_decoration.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using StructMemberOffsetDecorationTest = testing::Test;
+
+TEST_F(StructMemberOffsetDecorationTest, Creation) {
+  StructMemberOffsetDecoration d{2};
+  EXPECT_EQ(2, d.offset());
+}
+
+TEST_F(StructMemberOffsetDecorationTest, Is) {
+  StructMemberOffsetDecoration d{2};
+  EXPECT_TRUE(d.IsOffset());
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct_member_test.cc b/src/ast/struct_member_test.cc
new file mode 100644
index 0000000..9451d99
--- /dev/null
+++ b/src/ast/struct_member_test.cc
@@ -0,0 +1,92 @@
+// 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/ast/struct_member.h"
+
+#include <sstream>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/ast/struct_member_offset_decoration.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+
+using StructMemberTest = testing::Test;
+
+TEST_F(StructMemberTest, Creation) {
+  type::I32Type i32;
+  std::vector<std::unique_ptr<StructMemberDecoration>> decorations;
+  decorations.emplace_back(std::make_unique<StructMemberOffsetDecoration>(4));
+
+  StructMember st{"a", &i32, std::move(decorations)};
+  EXPECT_EQ(st.name(), "a");
+  EXPECT_EQ(st.type(), &i32);
+  EXPECT_EQ(st.decorations().size(), 1);
+  EXPECT_TRUE(st.decorations()[0]->IsOffset());
+  EXPECT_EQ(st.line(), 0);
+  EXPECT_EQ(st.column(), 0);
+}
+
+TEST_F(StructMemberTest, CreationWithSource) {
+  type::I32Type i32;
+  Source s{27, 4};
+
+  StructMember st{s, "a", &i32, {}};
+  EXPECT_EQ(st.name(), "a");
+  EXPECT_EQ(st.type(), &i32);
+  EXPECT_EQ(st.decorations().size(), 0);
+  EXPECT_EQ(st.line(), 27);
+  EXPECT_EQ(st.column(), 4);
+}
+
+TEST_F(StructMemberTest, IsValid) {
+  type::I32Type i32;
+  StructMember st{"a", &i32, {}};
+  EXPECT_TRUE(st.IsValid());
+}
+
+TEST_F(StructMemberTest, IsValid_EmptyName) {
+  type::I32Type i32;
+  StructMember st{"", &i32, {}};
+  EXPECT_FALSE(st.IsValid());
+}
+
+TEST_F(StructMemberTest, IsValid_NullType) {
+  StructMember st{"a", nullptr, {}};
+  EXPECT_FALSE(st.IsValid());
+}
+
+TEST_F(StructMemberTest, ToStr) {
+  type::I32Type i32;
+  std::vector<std::unique_ptr<StructMemberDecoration>> decorations;
+  decorations.emplace_back(std::make_unique<StructMemberOffsetDecoration>(4));
+
+  StructMember st{"a", &i32, std::move(decorations)};
+  std::ostringstream out;
+  st.to_str(out, 0);
+  EXPECT_EQ(out.str(), "StructMember{[[ offset 4 ]] a: __i32}\n");
+}
+
+TEST_F(StructMemberTest, ToStrNoDecorations) {
+  type::I32Type i32;
+  StructMember st{"a", &i32, {}};
+  std::ostringstream out;
+  st.to_str(out, 0);
+  EXPECT_EQ(out.str(), "StructMember{a: __i32}\n");
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/struct_test.cc b/src/ast/struct_test.cc
new file mode 100644
index 0000000..9802270
--- /dev/null
+++ b/src/ast/struct_test.cc
@@ -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.
+
+#include "src/ast/struct.h"
+
+#include <sstream>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/ast/struct_decoration.h"
+#include "src/ast/struct_member.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+
+using StructTest = testing::Test;
+
+TEST_F(StructTest, Creation) {
+  type::I32Type i32;
+  std::vector<std::unique_ptr<StructMember>> members;
+  members.push_back(std::make_unique<StructMember>(
+      "a", &i32, std::vector<std::unique_ptr<StructMemberDecoration>>()));
+
+  Struct s{StructDecoration::kNone, std::move(members)};
+  EXPECT_EQ(s.members().size(), 1);
+  EXPECT_EQ(s.decoration(), StructDecoration::kNone);
+  EXPECT_EQ(s.line(), 0);
+  EXPECT_EQ(s.column(), 0);
+}
+
+TEST_F(StructTest, CreationWithSource) {
+  type::I32Type i32;
+  Source source{27, 4};
+  std::vector<std::unique_ptr<StructMember>> members;
+  members.emplace_back(std::make_unique<StructMember>(
+      "a", &i32, std::vector<std::unique_ptr<StructMemberDecoration>>()));
+
+  Struct s{source, StructDecoration::kNone, std::move(members)};
+  EXPECT_EQ(s.members().size(), 1);
+  EXPECT_EQ(s.decoration(), StructDecoration::kNone);
+  EXPECT_EQ(s.line(), 27);
+  EXPECT_EQ(s.column(), 4);
+}
+
+TEST_F(StructTest, IsValid) {
+  Struct s;
+  EXPECT_TRUE(s.IsValid());
+}
+
+TEST_F(StructTest, ToStr) {
+  type::I32Type i32;
+  Source source{27, 4};
+  std::vector<std::unique_ptr<StructMember>> members;
+  members.emplace_back(std::make_unique<StructMember>(
+      "a", &i32, std::vector<std::unique_ptr<StructMemberDecoration>>()));
+
+  Struct s{source, StructDecoration::kNone, std::move(members)};
+
+  std::ostringstream out;
+  s.to_str(out, 0);
+  EXPECT_EQ(out.str(), R"(Struct{
+  StructMember{a: __i32}
+}
+)");
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/switch_statement.cc b/src/ast/switch_statement.cc
new file mode 100644
index 0000000..aabc242
--- /dev/null
+++ b/src/ast/switch_statement.cc
@@ -0,0 +1,58 @@
+// 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/ast/switch_statement.h"
+
+#include "src/ast/case_statement.h"
+
+namespace tint {
+namespace ast {
+
+SwitchStatement::SwitchStatement() : Statement() {}
+
+SwitchStatement::SwitchStatement(
+    std::unique_ptr<Expression> condition,
+    std::vector<std::unique_ptr<CaseStatement>> body)
+    : Statement(), condition_(std::move(condition)), body_(std::move(body)) {}
+
+SwitchStatement::SwitchStatement(
+    const Source& source,
+    std::unique_ptr<Expression> condition,
+    std::vector<std::unique_ptr<CaseStatement>> body)
+    : Statement(source),
+      condition_(std::move(condition)),
+      body_(std::move(body)) {}
+
+SwitchStatement::~SwitchStatement() = default;
+
+bool SwitchStatement::IsValid() const {
+  return condition_ != nullptr;
+}
+
+void SwitchStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Switch{" << std::endl;
+  condition_->to_str(out, indent + 2);
+  make_indent(out, indent + 2);
+  out << "{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/switch_statement.h b/src/ast/switch_statement.h
new file mode 100644
index 0000000..9d13995
--- /dev/null
+++ b/src/ast/switch_statement.h
@@ -0,0 +1,92 @@
+// 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_AST_SWITCH_STATEMENT_H_
+#define SRC_AST_SWITCH_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/statement.h"
+#include "src/ast/statement_condition.h"
+
+namespace tint {
+namespace ast {
+
+/// A switch statement
+class SwitchStatement : public Statement {
+ public:
+  /// Constructor
+  SwitchStatement();
+  /// Constructor
+  /// @param condition the switch condition
+  /// @param body the switch body
+  SwitchStatement(std::unique_ptr<Expression> condition,
+                  std::vector<std::unique_ptr<CaseStatement>> body);
+  /// Constructor
+  /// @param source the source information
+  /// @param condition the switch condition
+  /// @param body the switch body
+  SwitchStatement(const Source& source,
+                  std::unique_ptr<Expression> condition,
+                  std::vector<std::unique_ptr<CaseStatement>> body);
+  /// Move constructor
+  SwitchStatement(SwitchStatement&&) = default;
+  ~SwitchStatement() override;
+
+  /// Sets the condition for the switch statement
+  /// @param condition the condition to set
+  void set_condition(std::unique_ptr<Expression> condition) {
+    condition_ = std::move(condition);
+  }
+  /// @returns the switch condition or nullptr if none set
+  Expression* condition() const { return condition_.get(); }
+  /// @returns true if this is a default statement
+  bool IsDefault() const { return condition_ == nullptr; }
+
+  /// Sets the switch body
+  /// @param body the switch body
+  void set_body(std::vector<std::unique_ptr<CaseStatement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the Switch body
+  const std::vector<std::unique_ptr<CaseStatement>>& body() const {
+    return body_;
+  }
+
+  /// @returns true if this is a switch statement
+  bool IsSwitch() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  SwitchStatement(const SwitchStatement&) = delete;
+
+  std::unique_ptr<Expression> condition_;
+  std::vector<std::unique_ptr<CaseStatement>> body_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_SWITCH_STATEMENT_H_
diff --git a/src/ast/type/alias_type.cc b/src/ast/type/alias_type.cc
new file mode 100644
index 0000000..199557e
--- /dev/null
+++ b/src/ast/type/alias_type.cc
@@ -0,0 +1,32 @@
+// 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/ast/type/alias_type.h"
+
+#include <assert.h>
+
+namespace tint {
+namespace ast {
+namespace type {
+
+AliasType::AliasType(const std::string& name, Type* subtype)
+    : name_(name), subtype_(subtype) {
+  assert(subtype_);
+}
+
+AliasType::~AliasType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/alias_type.h b/src/ast/type/alias_type.h
new file mode 100644
index 0000000..a555951
--- /dev/null
+++ b/src/ast/type/alias_type.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_AST_TYPE_ALIAS_TYPE_H_
+#define SRC_AST_TYPE_ALIAS_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A type alias type. Holds a name a pointer to another type.
+class AliasType : public Type {
+ public:
+  /// Constructor
+  /// @param name the alias name
+  /// @param subtype the alias'd type
+  AliasType(const std::string& name, Type* subtype);
+  /// Move constructor
+  AliasType(AliasType&&) = default;
+  ~AliasType() override;
+
+  /// @returns true if the type is an alias type
+  bool IsAlias() const override { return true; }
+
+  /// @returns the alias name
+  const std::string& name() const { return name_; }
+  /// @returns the alias type
+  Type* type() const { return subtype_; }
+
+  /// @returns the name for this type
+  std::string type_name() const override {
+    return "__alias_" + name_ + subtype_->type_name();
+  }
+
+ private:
+  std::string name_;
+  Type* subtype_ = nullptr;
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_ALIAS_TYPE_H_
diff --git a/src/ast/type/alias_type_test.cc b/src/ast/type/alias_type_test.cc
new file mode 100644
index 0000000..e3c3126
--- /dev/null
+++ b/src/ast/type/alias_type_test.cc
@@ -0,0 +1,58 @@
+// 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/ast/type/alias_type.h"
+
+#include "gtest/gtest.h"
+#include "src/ast/type/i32_type.h"
+#include "src/ast/type/u32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using AliasTypeTest = testing::Test;
+
+TEST_F(AliasTypeTest, Create) {
+  U32Type u32;
+  AliasType a{"a_type", &u32};
+  EXPECT_EQ(a.name(), "a_type");
+  EXPECT_EQ(a.type(), &u32);
+}
+
+TEST_F(AliasTypeTest, Is) {
+  I32Type i32;
+
+  AliasType at{"a", &i32};
+  EXPECT_TRUE(at.IsAlias());
+  EXPECT_FALSE(at.IsArray());
+  EXPECT_FALSE(at.IsBool());
+  EXPECT_FALSE(at.IsF32());
+  EXPECT_FALSE(at.IsI32());
+  EXPECT_FALSE(at.IsMatrix());
+  EXPECT_FALSE(at.IsPointer());
+  EXPECT_FALSE(at.IsStruct());
+  EXPECT_FALSE(at.IsU32());
+  EXPECT_FALSE(at.IsVector());
+}
+
+TEST_F(AliasTypeTest, TypeName) {
+  I32Type i32;
+  AliasType at{"Particle", &i32};
+  EXPECT_EQ(at.type_name(), "__alias_Particle__i32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/array_type.cc b/src/ast/type/array_type.cc
new file mode 100644
index 0000000..c9eb6b6
--- /dev/null
+++ b/src/ast/type/array_type.cc
@@ -0,0 +1,30 @@
+// 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/ast/type/array_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+ArrayType::ArrayType(Type* subtype) : subtype_(subtype) {}
+
+ArrayType::ArrayType(Type* subtype, size_t size)
+    : subtype_(subtype), size_(size) {}
+
+ArrayType::~ArrayType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/array_type.h b/src/ast/type/array_type.h
new file mode 100644
index 0000000..28d25e0
--- /dev/null
+++ b/src/ast/type/array_type.h
@@ -0,0 +1,73 @@
+// 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_AST_TYPE_ARRAY_TYPE_H_
+#define SRC_AST_TYPE_ARRAY_TYPE_H_
+
+#include <assert.h>
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// An array type. If size is zero then it is a runtime array.
+class ArrayType : public Type {
+ public:
+  /// Constructor for runtime array
+  /// @param subtype the type of the array elements
+  explicit ArrayType(Type* subtype);
+  /// Constructor
+  /// @param subtype the type of the array elements
+  /// @param size the number of elements in the array
+  ArrayType(Type* subtype, size_t size);
+  /// Move constructor
+  ArrayType(ArrayType&&) = default;
+  ~ArrayType() override;
+
+  /// @returns true if the type is an array type
+  bool IsArray() const override { return true; }
+  /// @returns true if this is a runtime array.
+  /// i.e. the size is determined at runtime
+  bool IsRuntimeArray() const { return size_ == 0; }
+
+  /// @returns the array type
+  Type* type() const { return subtype_; }
+  /// @returns the array size. Size is 0 for a runtime array
+  size_t size() const { return size_; }
+
+  /// @returns the name for th type
+  std::string type_name() const override {
+    assert(subtype_);
+
+    std::string type_name = "__array" + subtype_->type_name();
+    if (!IsRuntimeArray())
+      type_name += "_" + std::to_string(size_);
+
+    return type_name;
+  }
+
+ private:
+  Type* subtype_ = nullptr;
+  size_t size_ = 0;
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_ARRAY_TYPE_H_
diff --git a/src/ast/type/array_type_test.cc b/src/ast/type/array_type_test.cc
new file mode 100644
index 0000000..5495f5b
--- /dev/null
+++ b/src/ast/type/array_type_test.cc
@@ -0,0 +1,69 @@
+// 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/ast/type/array_type.h"
+
+#include "gtest/gtest.h"
+#include "src/ast/type/i32_type.h"
+#include "src/ast/type/u32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using ArrayTypeTest = testing::Test;
+
+TEST_F(ArrayTypeTest, CreateSizedArray) {
+  U32Type u32;
+  ArrayType arr{&u32, 3};
+  EXPECT_EQ(arr.type(), &u32);
+  EXPECT_EQ(arr.size(), 3);
+  EXPECT_TRUE(arr.IsArray());
+  EXPECT_FALSE(arr.IsRuntimeArray());
+}
+
+TEST_F(ArrayTypeTest, CreateRuntimeArray) {
+  U32Type u32;
+  ArrayType arr{&u32};
+  EXPECT_EQ(arr.type(), &u32);
+  EXPECT_EQ(arr.size(), 0);
+  EXPECT_TRUE(arr.IsArray());
+  EXPECT_TRUE(arr.IsRuntimeArray());
+}
+
+TEST_F(ArrayTypeTest, Is) {
+  I32Type i32;
+
+  ArrayType arr{&i32, 3};
+  EXPECT_FALSE(arr.IsAlias());
+  EXPECT_TRUE(arr.IsArray());
+  EXPECT_FALSE(arr.IsBool());
+  EXPECT_FALSE(arr.IsF32());
+  EXPECT_FALSE(arr.IsI32());
+  EXPECT_FALSE(arr.IsMatrix());
+  EXPECT_FALSE(arr.IsPointer());
+  EXPECT_FALSE(arr.IsStruct());
+  EXPECT_FALSE(arr.IsU32());
+  EXPECT_FALSE(arr.IsVector());
+}
+
+TEST_F(ArrayTypeTest, TypeName) {
+  I32Type i32;
+  ArrayType arr{&i32, 3};
+  EXPECT_EQ(arr.type_name(), "__array__i32_3");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/bool_type.cc b/src/ast/type/bool_type.cc
new file mode 100644
index 0000000..d584181
--- /dev/null
+++ b/src/ast/type/bool_type.cc
@@ -0,0 +1,27 @@
+// 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/ast/type/bool_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+BoolType::BoolType() = default;
+
+BoolType::~BoolType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/bool_type.h b/src/ast/type/bool_type.h
new file mode 100644
index 0000000..79c4d63
--- /dev/null
+++ b/src/ast/type/bool_type.h
@@ -0,0 +1,46 @@
+// 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_AST_TYPE_BOOL_TYPE_H_
+#define SRC_AST_TYPE_BOOL_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A boolean type
+class BoolType : public Type {
+ public:
+  /// Constructor
+  BoolType();
+  /// Move constructor
+  BoolType(BoolType&&) = default;
+  ~BoolType() override;
+
+  /// @returns true if the type is a bool type
+  bool IsBool() const override { return true; }
+
+  /// @returns the name for this type
+  std::string type_name() const override { return "__bool"; }
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_BOOL_TYPE_H_
diff --git a/src/ast/type/bool_type_test.cc b/src/ast/type/bool_type_test.cc
new file mode 100644
index 0000000..6aacfe8
--- /dev/null
+++ b/src/ast/type/bool_type_test.cc
@@ -0,0 +1,46 @@
+// 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/ast/type/bool_type.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using BoolTypeTest = testing::Test;
+
+TEST_F(BoolTypeTest, Is) {
+  BoolType b;
+  EXPECT_FALSE(b.IsAlias());
+  EXPECT_FALSE(b.IsArray());
+  EXPECT_TRUE(b.IsBool());
+  EXPECT_FALSE(b.IsF32());
+  EXPECT_FALSE(b.IsI32());
+  EXPECT_FALSE(b.IsMatrix());
+  EXPECT_FALSE(b.IsPointer());
+  EXPECT_FALSE(b.IsStruct());
+  EXPECT_FALSE(b.IsU32());
+  EXPECT_FALSE(b.IsVector());
+}
+
+TEST_F(BoolTypeTest, TypeName) {
+  BoolType b;
+  EXPECT_EQ(b.type_name(), "__bool");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/f32_type.cc b/src/ast/type/f32_type.cc
new file mode 100644
index 0000000..065c22e
--- /dev/null
+++ b/src/ast/type/f32_type.cc
@@ -0,0 +1,27 @@
+// 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/ast/type/f32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+F32Type::F32Type() = default;
+
+F32Type::~F32Type() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/f32_type.h b/src/ast/type/f32_type.h
new file mode 100644
index 0000000..881ec4a
--- /dev/null
+++ b/src/ast/type/f32_type.h
@@ -0,0 +1,46 @@
+// 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_AST_TYPE_F32_TYPE_H_
+#define SRC_AST_TYPE_F32_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A float 32 type
+class F32Type : public Type {
+ public:
+  /// Constructor
+  F32Type();
+  /// Move constructor
+  F32Type(F32Type&&) = default;
+  ~F32Type() override;
+
+  /// @returns true if the type is an f32 type
+  bool IsF32() const override { return true; }
+
+  /// @returns the name for this type
+  std::string type_name() const override { return "__f32"; }
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_F32_TYPE_H_
diff --git a/src/ast/type/f32_type_test.cc b/src/ast/type/f32_type_test.cc
new file mode 100644
index 0000000..a5287f0
--- /dev/null
+++ b/src/ast/type/f32_type_test.cc
@@ -0,0 +1,46 @@
+// 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/ast/type/f32_type.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using F32TypeTest = testing::Test;
+
+TEST_F(F32TypeTest, Is) {
+  F32Type f;
+  EXPECT_FALSE(f.IsAlias());
+  EXPECT_FALSE(f.IsArray());
+  EXPECT_FALSE(f.IsBool());
+  EXPECT_TRUE(f.IsF32());
+  EXPECT_FALSE(f.IsI32());
+  EXPECT_FALSE(f.IsMatrix());
+  EXPECT_FALSE(f.IsPointer());
+  EXPECT_FALSE(f.IsStruct());
+  EXPECT_FALSE(f.IsU32());
+  EXPECT_FALSE(f.IsVector());
+}
+
+TEST_F(F32TypeTest, TypeName) {
+  F32Type f;
+  EXPECT_EQ(f.type_name(), "__f32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/i32_type.cc b/src/ast/type/i32_type.cc
new file mode 100644
index 0000000..0a7194d
--- /dev/null
+++ b/src/ast/type/i32_type.cc
@@ -0,0 +1,27 @@
+// 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/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+I32Type::I32Type() = default;
+
+I32Type::~I32Type() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/i32_type.h b/src/ast/type/i32_type.h
new file mode 100644
index 0000000..ea60c13
--- /dev/null
+++ b/src/ast/type/i32_type.h
@@ -0,0 +1,46 @@
+// 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_AST_TYPE_I32_TYPE_H_
+#define SRC_AST_TYPE_I32_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A signed int 32 type.
+class I32Type : public Type {
+ public:
+  /// Constructor
+  I32Type();
+  /// Move constructor
+  I32Type(I32Type&&) = default;
+  ~I32Type() override;
+
+  /// @returns true if the type is an i32 type
+  bool IsI32() const override { return true; }
+
+  /// @returns the name for this type
+  std::string type_name() const override { return "__i32"; }
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_I32_TYPE_H_
diff --git a/src/ast/type/i32_type_test.cc b/src/ast/type/i32_type_test.cc
new file mode 100644
index 0000000..67f2483
--- /dev/null
+++ b/src/ast/type/i32_type_test.cc
@@ -0,0 +1,46 @@
+// 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/ast/type/i32_type.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using I32TypeTest = testing::Test;
+
+TEST_F(I32TypeTest, Is) {
+  I32Type i;
+  EXPECT_FALSE(i.IsAlias());
+  EXPECT_FALSE(i.IsArray());
+  EXPECT_FALSE(i.IsBool());
+  EXPECT_FALSE(i.IsF32());
+  EXPECT_TRUE(i.IsI32());
+  EXPECT_FALSE(i.IsMatrix());
+  EXPECT_FALSE(i.IsPointer());
+  EXPECT_FALSE(i.IsStruct());
+  EXPECT_FALSE(i.IsU32());
+  EXPECT_FALSE(i.IsVector());
+}
+
+TEST_F(I32TypeTest, TypeName) {
+  I32Type i;
+  EXPECT_EQ(i.type_name(), "__i32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/matrix_type.cc b/src/ast/type/matrix_type.cc
new file mode 100644
index 0000000..64aef3e
--- /dev/null
+++ b/src/ast/type/matrix_type.cc
@@ -0,0 +1,35 @@
+// 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/ast/type/matrix_type.h"
+
+#include <assert.h>
+
+namespace tint {
+namespace ast {
+namespace type {
+
+MatrixType::MatrixType(Type* subtype, size_t rows, size_t columns)
+    : subtype_(subtype), rows_(rows), columns_(columns) {
+  assert(rows > 1);
+  assert(rows < 5);
+  assert(columns > 1);
+  assert(columns < 5);
+}
+
+MatrixType::~MatrixType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/matrix_type.h b/src/ast/type/matrix_type.h
new file mode 100644
index 0000000..f37d12a
--- /dev/null
+++ b/src/ast/type/matrix_type.h
@@ -0,0 +1,64 @@
+// 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_AST_TYPE_MATRIX_TYPE_H_
+#define SRC_AST_TYPE_MATRIX_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A matrix type
+class MatrixType : public Type {
+ public:
+  /// Constructor
+  /// @param subtype type matrix type
+  /// @param rows the number of rows in the matrix
+  /// @param columns the number of columns in the matrix
+  MatrixType(Type* subtype, size_t rows, size_t columns);
+  /// Move constructor
+  MatrixType(MatrixType&&) = default;
+  ~MatrixType() override;
+
+  /// @returns true if the type is a matrix type
+  bool IsMatrix() const override { return true; }
+
+  /// @returns the type of the matrix
+  Type* type() const { return subtype_; }
+  /// @returns the number of rows in the matrix
+  size_t rows() const { return rows_; }
+  /// @returns the number of columns in the matrix
+  size_t columns() const { return columns_; }
+
+  /// @returns the name for this type
+  std::string type_name() const override {
+    return "__mat_" + std::to_string(rows_) + "_" + std::to_string(columns_) +
+           subtype_->type_name();
+  }
+
+ private:
+  Type* subtype_ = nullptr;
+  size_t rows_ = 2;
+  size_t columns_ = 2;
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_MATRIX_TYPE_H_
diff --git a/src/ast/type/matrix_type_test.cc b/src/ast/type/matrix_type_test.cc
new file mode 100644
index 0000000..0bdb7ea
--- /dev/null
+++ b/src/ast/type/matrix_type_test.cc
@@ -0,0 +1,57 @@
+// 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/ast/type/matrix_type.h"
+
+#include "gtest/gtest.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using MatrixTypeTest = testing::Test;
+
+TEST_F(MatrixTypeTest, Creation) {
+  I32Type i32;
+  MatrixType m{&i32, 2, 4};
+  EXPECT_EQ(m.type(), &i32);
+  EXPECT_EQ(m.rows(), 2);
+  EXPECT_EQ(m.columns(), 4);
+}
+
+TEST_F(MatrixTypeTest, Is) {
+  I32Type i32;
+  MatrixType m{&i32, 2, 3};
+  EXPECT_FALSE(m.IsAlias());
+  EXPECT_FALSE(m.IsArray());
+  EXPECT_FALSE(m.IsBool());
+  EXPECT_FALSE(m.IsF32());
+  EXPECT_FALSE(m.IsI32());
+  EXPECT_TRUE(m.IsMatrix());
+  EXPECT_FALSE(m.IsPointer());
+  EXPECT_FALSE(m.IsStruct());
+  EXPECT_FALSE(m.IsU32());
+  EXPECT_FALSE(m.IsVector());
+}
+
+TEST_F(MatrixTypeTest, TypeName) {
+  I32Type i32;
+  MatrixType m{&i32, 2, 3};
+  EXPECT_EQ(m.type_name(), "__mat_2_3__i32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/pointer_type.cc b/src/ast/type/pointer_type.cc
new file mode 100644
index 0000000..2b8e9ce
--- /dev/null
+++ b/src/ast/type/pointer_type.cc
@@ -0,0 +1,28 @@
+// 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/ast/type/pointer_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+PointerType::PointerType(Type* subtype, StorageClass storage_class)
+    : subtype_(subtype), storage_class_(storage_class) {}
+
+PointerType::~PointerType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/pointer_type.h b/src/ast/type/pointer_type.h
new file mode 100644
index 0000000..40ea116
--- /dev/null
+++ b/src/ast/type/pointer_type.h
@@ -0,0 +1,63 @@
+// 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_AST_TYPE_POINTER_TYPE_H_
+#define SRC_AST_TYPE_POINTER_TYPE_H_
+
+#include <sstream>
+#include <string>
+
+#include "src/ast/storage_class.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A pointer type.
+class PointerType : public Type {
+ public:
+  /// Construtor
+  /// @param subtype the pointee type
+  /// @param storage_class the storage class of the pointer
+  explicit PointerType(Type* subtype, StorageClass storage_class);
+  /// Move constructor
+  PointerType(PointerType&&) = default;
+  ~PointerType() override;
+
+  /// @returns true if the type is a pointer type
+  bool IsPointer() const override { return true; }
+
+  /// @returns the pointee type
+  Type* type() const { return subtype_; }
+  /// @returns the storage class of the pointer
+  StorageClass storage_class() const { return storage_class_; }
+
+  /// @returns the name for this type
+  std::string type_name() const override {
+    std::ostringstream out;
+    out << "__ptr_" << storage_class_ << subtype_->type_name();
+    return out.str();
+  }
+
+ private:
+  Type* subtype_;
+  StorageClass storage_class_;
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_POINTER_TYPE_H_
diff --git a/src/ast/type/pointer_type_test.cc b/src/ast/type/pointer_type_test.cc
new file mode 100644
index 0000000..52d167f
--- /dev/null
+++ b/src/ast/type/pointer_type_test.cc
@@ -0,0 +1,56 @@
+// 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/ast/type/pointer_type.h"
+
+#include "gtest/gtest.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using PointerTypeTest = testing::Test;
+
+TEST_F(PointerTypeTest, Creation) {
+  I32Type i32;
+  PointerType p{&i32, StorageClass::kStorageBuffer};
+  EXPECT_EQ(p.type(), &i32);
+  EXPECT_EQ(p.storage_class(), StorageClass::kStorageBuffer);
+}
+
+TEST_F(PointerTypeTest, Is) {
+  I32Type i32;
+  PointerType p{&i32, StorageClass::kFunction};
+  EXPECT_FALSE(p.IsAlias());
+  EXPECT_FALSE(p.IsArray());
+  EXPECT_FALSE(p.IsBool());
+  EXPECT_FALSE(p.IsF32());
+  EXPECT_FALSE(p.IsI32());
+  EXPECT_FALSE(p.IsMatrix());
+  EXPECT_TRUE(p.IsPointer());
+  EXPECT_FALSE(p.IsStruct());
+  EXPECT_FALSE(p.IsU32());
+  EXPECT_FALSE(p.IsVector());
+}
+
+TEST_F(PointerTypeTest, TypeName) {
+  I32Type i32;
+  PointerType p{&i32, StorageClass::kWorkgroup};
+  EXPECT_EQ(p.type_name(), "__ptr_workgroup__i32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/struct_type.cc b/src/ast/type/struct_type.cc
new file mode 100644
index 0000000..d2fcfdc
--- /dev/null
+++ b/src/ast/type/struct_type.cc
@@ -0,0 +1,30 @@
+// 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/ast/type/struct_type.h"
+
+#include <utility>
+
+namespace tint {
+namespace ast {
+namespace type {
+
+StructType::StructType(std::unique_ptr<Struct> impl)
+    : struct_(std::move(impl)) {}
+
+StructType::~StructType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/struct_type.h b/src/ast/type/struct_type.h
new file mode 100644
index 0000000..c33cd27
--- /dev/null
+++ b/src/ast/type/struct_type.h
@@ -0,0 +1,62 @@
+// 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_AST_TYPE_STRUCT_TYPE_H_
+#define SRC_AST_TYPE_STRUCT_TYPE_H_
+
+#include <memory>
+#include <string>
+
+#include "src/ast/struct.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A structure type
+class StructType : public Type {
+ public:
+  /// Constructor
+  /// @param impl the struct data
+  explicit StructType(std::unique_ptr<Struct> impl);
+  /// Move constructor
+  StructType(StructType&&) = default;
+  ~StructType() override;
+
+  /// Sets the name of the struct
+  /// @param name the name to set
+  void set_name(const std::string& name) { name_ = name; }
+  /// @returns the struct name
+  const std::string& name() const { return name_; }
+
+  /// @returns true if the type is a struct type
+  bool IsStruct() const override { return true; }
+
+  /// @returns the struct name
+  Struct* impl() const { return struct_.get(); }
+
+  /// @returns the name for th type
+  std::string type_name() const override { return "__struct_" + name_; }
+
+ private:
+  std::string name_;
+  std::unique_ptr<Struct> struct_;
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_STRUCT_TYPE_H_
diff --git a/src/ast/type/struct_type_test.cc b/src/ast/type/struct_type_test.cc
new file mode 100644
index 0000000..1721079
--- /dev/null
+++ b/src/ast/type/struct_type_test.cc
@@ -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.
+
+#include "src/ast/type/struct_type.h"
+
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using StructTypeTest = testing::Test;
+
+TEST_F(StructTypeTest, Creation) {
+  auto impl = std::make_unique<Struct>();
+  auto ptr = impl.get();
+  StructType s{std::move(impl)};
+  EXPECT_EQ(s.impl(), ptr);
+}
+
+TEST_F(StructTypeTest, Is) {
+  auto impl = std::make_unique<Struct>();
+  StructType s{std::move(impl)};
+  EXPECT_FALSE(s.IsAlias());
+  EXPECT_FALSE(s.IsArray());
+  EXPECT_FALSE(s.IsBool());
+  EXPECT_FALSE(s.IsF32());
+  EXPECT_FALSE(s.IsI32());
+  EXPECT_FALSE(s.IsMatrix());
+  EXPECT_FALSE(s.IsPointer());
+  EXPECT_TRUE(s.IsStruct());
+  EXPECT_FALSE(s.IsU32());
+  EXPECT_FALSE(s.IsVector());
+}
+
+TEST_F(StructTypeTest, TypeName) {
+  auto impl = std::make_unique<Struct>();
+  StructType s{std::move(impl)};
+  s.set_name("my_struct");
+  EXPECT_EQ(s.type_name(), "__struct_my_struct");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/type.cc b/src/ast/type/type.cc
new file mode 100644
index 0000000..00fe94d
--- /dev/null
+++ b/src/ast/type/type.cc
@@ -0,0 +1,96 @@
+// 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/ast/type/type.h"
+
+#include <assert.h>
+
+#include "src/ast/type/alias_type.h"
+#include "src/ast/type/array_type.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/matrix_type.h"
+#include "src/ast/type/pointer_type.h"
+#include "src/ast/type/struct_type.h"
+#include "src/ast/type/u32_type.h"
+#include "src/ast/type/vector_type.h"
+#include "src/ast/type/void_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+Type::Type() = default;
+
+Type::~Type() = default;
+
+AliasType* Type::AsAlias() {
+  assert(IsAlias());
+  return static_cast<AliasType*>(this);
+}
+
+ArrayType* Type::AsArray() {
+  assert(IsArray());
+  return static_cast<ArrayType*>(this);
+}
+
+BoolType* Type::AsBool() {
+  assert(IsBool());
+  return static_cast<BoolType*>(this);
+}
+
+F32Type* Type::AsF32() {
+  assert(IsF32());
+  return static_cast<F32Type*>(this);
+}
+
+I32Type* Type::AsI32() {
+  assert(IsI32());
+  return static_cast<I32Type*>(this);
+}
+
+MatrixType* Type::AsMatrix() {
+  assert(IsMatrix());
+  return static_cast<MatrixType*>(this);
+}
+
+PointerType* Type::AsPointer() {
+  assert(IsPointer());
+  return static_cast<PointerType*>(this);
+}
+
+StructType* Type::AsStruct() {
+  assert(IsStruct());
+  return static_cast<StructType*>(this);
+}
+
+U32Type* Type::AsU32() {
+  assert(IsU32());
+  return static_cast<U32Type*>(this);
+}
+
+VectorType* Type::AsVector() {
+  assert(IsVector());
+  return static_cast<VectorType*>(this);
+}
+
+VoidType* Type::AsVoid() {
+  assert(IsVoid());
+  return static_cast<VoidType*>(this);
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/type.h b/src/ast/type/type.h
new file mode 100644
index 0000000..cf66f3b
--- /dev/null
+++ b/src/ast/type/type.h
@@ -0,0 +1,100 @@
+// 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_AST_TYPE_TYPE_H_
+#define SRC_AST_TYPE_TYPE_H_
+
+#include <string>
+
+namespace tint {
+namespace ast {
+namespace type {
+
+class AliasType;
+class ArrayType;
+class BoolType;
+class F32Type;
+class I32Type;
+class MatrixType;
+class PointerType;
+class StructType;
+class U32Type;
+class VectorType;
+class VoidType;
+
+/// Base class for a type in the system
+class Type {
+ public:
+  /// Move constructor
+  Type(Type&&) = default;
+  virtual ~Type();
+
+  /// @returns true if the type is an alias type
+  virtual bool IsAlias() const { return false; }
+  /// @returns true if the type is an array type
+  virtual bool IsArray() const { return false; }
+  /// @returns true if the type is a bool type
+  virtual bool IsBool() const { return false; }
+  /// @returns true if the type is an f32 type
+  virtual bool IsF32() const { return false; }
+  /// @returns true if the type is an i32 type
+  virtual bool IsI32() const { return false; }
+  /// @returns true if the type is a matrix type
+  virtual bool IsMatrix() const { return false; }
+  /// @returns true if the type is a ptr type
+  virtual bool IsPointer() const { return false; }
+  /// @returns true if the type is a struct type
+  virtual bool IsStruct() const { return false; }
+  /// @returns true if the type is a u32 type
+  virtual bool IsU32() const { return false; }
+  /// @returns true if the type is a vec type
+  virtual bool IsVector() const { return false; }
+  /// @returns true if the type is a void type
+  virtual bool IsVoid() const { return false; }
+
+  /// @returns the name for this type
+  virtual std::string type_name() const = 0;
+
+  /// @returns the type as an alias type
+  AliasType* AsAlias();
+  /// @returns the type as an array type
+  ArrayType* AsArray();
+  /// @returns the type as a bool type
+  BoolType* AsBool();
+  /// @returns the type as a f32 type
+  F32Type* AsF32();
+  /// @returns the type as an i32 type
+  I32Type* AsI32();
+  /// @returns the type as a matrix type
+  MatrixType* AsMatrix();
+  /// @returns the type as a pointer type
+  PointerType* AsPointer();
+  /// @returns the type as a struct type
+  StructType* AsStruct();
+  /// @returns the type as a u32 type
+  U32Type* AsU32();
+  /// @returns the type as a vector type
+  VectorType* AsVector();
+  /// @returns the type as a void type
+  VoidType* AsVoid();
+
+ protected:
+  Type();
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_TYPE_H_
diff --git a/src/ast/type/u32_type.cc b/src/ast/type/u32_type.cc
new file mode 100644
index 0000000..b155b1d
--- /dev/null
+++ b/src/ast/type/u32_type.cc
@@ -0,0 +1,27 @@
+// 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/ast/type/u32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+U32Type::U32Type() = default;
+
+U32Type::~U32Type() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/u32_type.h b/src/ast/type/u32_type.h
new file mode 100644
index 0000000..b0d9440
--- /dev/null
+++ b/src/ast/type/u32_type.h
@@ -0,0 +1,46 @@
+// 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_AST_TYPE_U32_TYPE_H_
+#define SRC_AST_TYPE_U32_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A unsigned int 32 type.
+class U32Type : public Type {
+ public:
+  /// Constructor
+  U32Type();
+  /// Move constructor
+  U32Type(U32Type&&) = default;
+  ~U32Type() override;
+
+  /// @returns true if the type is a u32 type
+  bool IsU32() const override { return true; }
+
+  /// @returns the name for th type
+  std::string type_name() const override { return "__u32"; }
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_U32_TYPE_H_
diff --git a/src/ast/type/u32_type_test.cc b/src/ast/type/u32_type_test.cc
new file mode 100644
index 0000000..5f4508e
--- /dev/null
+++ b/src/ast/type/u32_type_test.cc
@@ -0,0 +1,46 @@
+// 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/ast/type/u32_type.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using U32TypeTest = testing::Test;
+
+TEST_F(U32TypeTest, Is) {
+  U32Type u;
+  EXPECT_FALSE(u.IsAlias());
+  EXPECT_FALSE(u.IsArray());
+  EXPECT_FALSE(u.IsBool());
+  EXPECT_FALSE(u.IsF32());
+  EXPECT_FALSE(u.IsI32());
+  EXPECT_FALSE(u.IsMatrix());
+  EXPECT_FALSE(u.IsPointer());
+  EXPECT_FALSE(u.IsStruct());
+  EXPECT_TRUE(u.IsU32());
+  EXPECT_FALSE(u.IsVector());
+}
+
+TEST_F(U32TypeTest, TypeName) {
+  U32Type u;
+  EXPECT_EQ(u.type_name(), "__u32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/vector_type.cc b/src/ast/type/vector_type.cc
new file mode 100644
index 0000000..8530214
--- /dev/null
+++ b/src/ast/type/vector_type.cc
@@ -0,0 +1,33 @@
+// 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/ast/type/vector_type.h"
+
+#include <assert.h>
+
+namespace tint {
+namespace ast {
+namespace type {
+
+VectorType::VectorType(Type* subtype, size_t size)
+    : subtype_(subtype), size_(size) {
+  assert(size_ > 1);
+  assert(size_ < 5);
+}
+
+VectorType::~VectorType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/vector_type.h b/src/ast/type/vector_type.h
new file mode 100644
index 0000000..a773275
--- /dev/null
+++ b/src/ast/type/vector_type.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_AST_TYPE_VECTOR_TYPE_H_
+#define SRC_AST_TYPE_VECTOR_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A vector type.
+class VectorType : public Type {
+ public:
+  /// Constructor
+  /// @param subtype the vector element type
+  /// @param size the number of elements in the vector
+  VectorType(Type* subtype, size_t size);
+  /// Move constructor
+  VectorType(VectorType&&) = default;
+  ~VectorType() override;
+
+  /// @returns true if the type is a vector type
+  bool IsVector() const override { return true; }
+
+  /// @returns the type of the vector elements
+  Type* type() const { return subtype_; }
+  /// @returns the size of the vector
+  size_t size() const { return size_; }
+
+  /// @returns the name for th type
+  std::string type_name() const override {
+    return "__vec_" + std::to_string(size_) + subtype_->type_name();
+  }
+
+ private:
+  Type* subtype_ = nullptr;
+  size_t size_ = 2;
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_VECTOR_TYPE_H_
diff --git a/src/ast/type/vector_type_test.cc b/src/ast/type/vector_type_test.cc
new file mode 100644
index 0000000..bc08383
--- /dev/null
+++ b/src/ast/type/vector_type_test.cc
@@ -0,0 +1,56 @@
+// 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/ast/type/vector_type.h"
+
+#include "gtest/gtest.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+using VectorTypeTest = testing::Test;
+
+TEST_F(VectorTypeTest, Creation) {
+  I32Type i32;
+  VectorType v{&i32, 2};
+  EXPECT_EQ(v.type(), &i32);
+  EXPECT_EQ(v.size(), 2);
+}
+
+TEST_F(VectorTypeTest, Is) {
+  I32Type i32;
+  VectorType v{&i32, 4};
+  EXPECT_FALSE(v.IsAlias());
+  EXPECT_FALSE(v.IsArray());
+  EXPECT_FALSE(v.IsBool());
+  EXPECT_FALSE(v.IsF32());
+  EXPECT_FALSE(v.IsI32());
+  EXPECT_FALSE(v.IsMatrix());
+  EXPECT_FALSE(v.IsPointer());
+  EXPECT_FALSE(v.IsStruct());
+  EXPECT_FALSE(v.IsU32());
+  EXPECT_TRUE(v.IsVector());
+}
+
+TEST_F(VectorTypeTest, TypeName) {
+  I32Type i32;
+  VectorType v{&i32, 3};
+  EXPECT_EQ(v.type_name(), "__vec_3__i32");
+}
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/void_type.cc b/src/ast/type/void_type.cc
new file mode 100644
index 0000000..f41a9ba
--- /dev/null
+++ b/src/ast/type/void_type.cc
@@ -0,0 +1,27 @@
+// 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/ast/type/void_type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+VoidType::VoidType() = default;
+
+VoidType::~VoidType() = default;
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type/void_type.h b/src/ast/type/void_type.h
new file mode 100644
index 0000000..702a9b5
--- /dev/null
+++ b/src/ast/type/void_type.h
@@ -0,0 +1,46 @@
+// 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_AST_TYPE_VOID_TYPE_H_
+#define SRC_AST_TYPE_VOID_TYPE_H_
+
+#include <string>
+
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+namespace type {
+
+/// A void type
+class VoidType : public Type {
+ public:
+  /// Constructor
+  VoidType();
+  /// Move constructor
+  VoidType(VoidType&&) = default;
+  ~VoidType() override;
+
+  /// @returns true if the type is a void type
+  bool IsVoid() const override { return true; }
+
+  /// @returns the name for this type
+  std::string type_name() const override { return "__void"; }
+};
+
+}  // namespace type
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_VOID_TYPE_H_
diff --git a/src/ast/type_initializer_expression.cc b/src/ast/type_initializer_expression.cc
new file mode 100644
index 0000000..0b092f3
--- /dev/null
+++ b/src/ast/type_initializer_expression.cc
@@ -0,0 +1,51 @@
+// 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/ast/type_initializer_expression.h"
+
+namespace tint {
+namespace ast {
+
+TypeInitializerExpression::TypeInitializerExpression(
+    type::Type* type,
+    std::vector<std::unique_ptr<Expression>> values)
+    : InitializerExpression(), type_(type), values_(std::move(values)) {}
+
+TypeInitializerExpression::TypeInitializerExpression(
+    const Source& source,
+    type::Type* type,
+    std::vector<std::unique_ptr<Expression>> values)
+    : InitializerExpression(source), type_(type), values_(std::move(values)) {}
+
+TypeInitializerExpression::~TypeInitializerExpression() = default;
+
+bool TypeInitializerExpression::IsValid() const {
+  return values_.size() > 0;
+}
+
+void TypeInitializerExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "TypeInitializer{" << std::endl;
+  make_indent(out, indent + 2);
+  out << type_->type_name() << std::endl;
+
+  for (const auto& val : values_) {
+    val->to_str(out, indent + 2);
+  }
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/type_initializer_expression.h b/src/ast/type_initializer_expression.h
new file mode 100644
index 0000000..9b7af2f
--- /dev/null
+++ b/src/ast/type_initializer_expression.h
@@ -0,0 +1,85 @@
+// 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_AST_TYPE_INITIALIZER_EXPRESSION_H_
+#define SRC_AST_TYPE_INITIALIZER_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/initializer_expression.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+
+/// A type specific initializer
+class TypeInitializerExpression : public InitializerExpression {
+ public:
+  /// Constructor
+  /// @param type the type
+  /// @param values the values
+  explicit TypeInitializerExpression(
+      type::Type* type,
+      std::vector<std::unique_ptr<Expression>> values);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param type the type
+  /// @param values the initializer values
+  TypeInitializerExpression(const Source& source,
+                            type::Type* type,
+                            std::vector<std::unique_ptr<Expression>> values);
+  /// Move constructor
+  TypeInitializerExpression(TypeInitializerExpression&&) = default;
+  ~TypeInitializerExpression() override;
+
+  /// @returns true if this is a type initializer
+  bool IsTypeInitializer() const override { return true; }
+
+  /// Set the type
+  /// @param type the type
+  void set_type(type::Type* type) { type_ = type; }
+  /// @returns the type
+  type::Type* type() const { return type_; }
+
+  /// Set the values
+  /// @param values the values
+  void set_values(std::vector<std::unique_ptr<Expression>> values) {
+    values_ = std::move(values);
+  }
+  /// @returns the values
+  const std::vector<std::unique_ptr<Expression>>& values() const {
+    return values_;
+  }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  TypeInitializerExpression(const TypeInitializerExpression&) = delete;
+
+  type::Type* type_;
+  std::vector<std::unique_ptr<Expression>> values_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_TYPE_INITIALIZER_EXPRESSION_H_
diff --git a/src/ast/uint_literal.cc b/src/ast/uint_literal.cc
new file mode 100644
index 0000000..273f9ca
--- /dev/null
+++ b/src/ast/uint_literal.cc
@@ -0,0 +1,29 @@
+// 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/ast/uint_literal.h"
+
+namespace tint {
+namespace ast {
+
+UintLiteral::UintLiteral(uint32_t value) : value_(value) {}
+
+UintLiteral::~UintLiteral() = default;
+
+std::string UintLiteral::to_str() const {
+  return std::to_string(value_);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/uint_literal.h b/src/ast/uint_literal.h
new file mode 100644
index 0000000..0b2394e
--- /dev/null
+++ b/src/ast/uint_literal.h
@@ -0,0 +1,49 @@
+// 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_AST_UINT_LITERAL_H_
+#define SRC_AST_UINT_LITERAL_H_
+
+#include <string>
+
+#include "src/ast/literal.h"
+
+namespace tint {
+namespace ast {
+
+/// A uint literal
+class UintLiteral : public Literal {
+ public:
+  /// Constructor
+  /// @param value the uint literals value
+  explicit UintLiteral(uint32_t value);
+  ~UintLiteral() override;
+
+  /// @returns true if this is a uint literal
+  bool IsUint() const override { return true; }
+
+  /// @returns the uint literal value
+  uint32_t value() const { return value_; }
+
+  /// @returns the literal as a string
+  std::string to_str() const override;
+
+ private:
+  uint32_t value_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UINT_LITERAL_H_
diff --git a/src/ast/uint_literal_test.cc b/src/ast/uint_literal_test.cc
new file mode 100644
index 0000000..04628c3
--- /dev/null
+++ b/src/ast/uint_literal_test.cc
@@ -0,0 +1,45 @@
+// 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/ast/uint_literal.h"
+
+#include "gtest/gtest.h"
+
+namespace tint {
+namespace ast {
+
+using UintLiteralTest = testing::Test;
+
+TEST_F(UintLiteralTest, Value) {
+  UintLiteral u{47};
+  ASSERT_TRUE(u.IsUint());
+  EXPECT_EQ(u.value(), 47);
+}
+
+TEST_F(UintLiteralTest, Is) {
+  UintLiteral u{42};
+  EXPECT_FALSE(u.IsBool());
+  EXPECT_FALSE(u.IsInt());
+  EXPECT_FALSE(u.IsFloat());
+  EXPECT_TRUE(u.IsUint());
+}
+
+TEST_F(UintLiteralTest, ToStr) {
+  UintLiteral i{42};
+
+  EXPECT_EQ(i.to_str(), "42");
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_derivative.cc b/src/ast/unary_derivative.cc
new file mode 100644
index 0000000..82ae23c
--- /dev/null
+++ b/src/ast/unary_derivative.cc
@@ -0,0 +1,39 @@
+// 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/ast/unary_derivative.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, UnaryDerivative mod) {
+  switch (mod) {
+    case UnaryDerivative::kDpdx: {
+      out << "dpdx";
+      break;
+    }
+    case UnaryDerivative::kDpdy: {
+      out << "dpdy";
+      break;
+    }
+    case UnaryDerivative::kFwidth: {
+      out << "fwidth";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_derivative.h b/src/ast/unary_derivative.h
new file mode 100644
index 0000000..741834c
--- /dev/null
+++ b/src/ast/unary_derivative.h
@@ -0,0 +1,31 @@
+// 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_AST_UNARY_DERIVATIVE_H_
+#define SRC_AST_UNARY_DERIVATIVE_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The unary derivative
+enum class UnaryDerivative { kDpdx = 0, kDpdy, kFwidth };
+
+std::ostream& operator<<(std::ostream& out, UnaryDerivative mod);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNARY_DERIVATIVE_H_
diff --git a/src/ast/unary_derivative_expression.cc b/src/ast/unary_derivative_expression.cc
new file mode 100644
index 0000000..1ae9a86
--- /dev/null
+++ b/src/ast/unary_derivative_expression.cc
@@ -0,0 +1,52 @@
+// 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/ast/unary_derivative_expression.h"
+
+namespace tint {
+namespace ast {
+
+UnaryDerivativeExpression::UnaryDerivativeExpression(
+    UnaryDerivative op,
+    DerivativeModifier mod,
+    std::unique_ptr<Expression> param)
+    : Expression(), op_(op), modifier_(mod), param_(std::move(param)) {}
+
+UnaryDerivativeExpression::UnaryDerivativeExpression(
+    const Source& source,
+    UnaryDerivative op,
+    DerivativeModifier mod,
+    std::unique_ptr<Expression> param)
+    : Expression(source), op_(op), modifier_(mod), param_(std::move(param)) {}
+
+UnaryDerivativeExpression::~UnaryDerivativeExpression() = default;
+
+bool UnaryDerivativeExpression::IsValid() const {
+  return true;
+}
+
+void UnaryDerivativeExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "UnaryDerivative{" << std::endl;
+  make_indent(out, indent + 2);
+  out << op_ << std::endl;
+  make_indent(out, indent + 2);
+  out << modifier_ << std::endl;
+  param_->to_str(out, indent);
+  make_indent(out, indent);
+  out << "}";
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_derivative_expression.h b/src/ast/unary_derivative_expression.h
new file mode 100644
index 0000000..f601286
--- /dev/null
+++ b/src/ast/unary_derivative_expression.h
@@ -0,0 +1,94 @@
+// 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_AST_UNARY_DERIVATIVE_EXPRESSION_H_
+#define SRC_AST_UNARY_DERIVATIVE_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/derivative_modifier.h"
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/unary_derivative.h"
+
+namespace tint {
+namespace ast {
+
+/// A unary derivative expression
+class UnaryDerivativeExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param op the op
+  /// @param mod the derivative modifier
+  /// @param param the param
+  UnaryDerivativeExpression(UnaryDerivative op,
+                            DerivativeModifier mod,
+                            std::unique_ptr<Expression> param);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param op the op
+  /// @param mod the derivative modifier
+  /// @param param the param
+  UnaryDerivativeExpression(const Source& source,
+                            UnaryDerivative op,
+                            DerivativeModifier mod,
+                            std::unique_ptr<Expression> param);
+  /// Move constructor
+  UnaryDerivativeExpression(UnaryDerivativeExpression&&) = default;
+  ~UnaryDerivativeExpression() override;
+
+  /// Sets the op
+  /// @param op the op
+  void set_op(UnaryDerivative op) { op_ = op; }
+  /// @returns the op
+  UnaryDerivative op() const { return op_; }
+
+  /// Sets the derivative modifier
+  /// @param mod the modifier
+  void set_modifier(DerivativeModifier mod) { modifier_ = mod; }
+  /// @returns the derivative modifier
+  DerivativeModifier modifier() const { return modifier_; }
+
+  /// Sets the param
+  /// @param param the param
+  void set_param(std::unique_ptr<Expression> param) {
+    param_ = std::move(param);
+  }
+  /// @returns the param
+  Expression* param() const { return param_.get(); }
+
+  /// @returns true if this is an as expression
+  bool IsUnaryDerivative() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  UnaryDerivativeExpression(const UnaryDerivativeExpression&) = delete;
+
+  UnaryDerivative op_ = UnaryDerivative::kDpdx;
+  DerivativeModifier modifier_ = DerivativeModifier::kNone;
+  std::unique_ptr<Expression> param_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNARY_DERIVATIVE_EXPRESSION_H_
diff --git a/src/ast/unary_method.cc b/src/ast/unary_method.cc
new file mode 100644
index 0000000..7ff4653
--- /dev/null
+++ b/src/ast/unary_method.cc
@@ -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.
+
+#include "src/ast/unary_method.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, UnaryMethod mod) {
+  switch (mod) {
+    case UnaryMethod::kAny: {
+      out << "any";
+      break;
+    }
+    case UnaryMethod::kAll: {
+      out << "all";
+      break;
+    }
+    case UnaryMethod::kIsNan: {
+      out << "is_nan";
+      break;
+    }
+    case UnaryMethod::kIsInf: {
+      out << "is_inf";
+      break;
+    }
+    case UnaryMethod::kIsFinite: {
+      out << "is_finite";
+      break;
+    }
+    case UnaryMethod::kIsNormal: {
+      out << "is_normal";
+      break;
+    }
+    case UnaryMethod::kDot: {
+      out << "dot";
+      break;
+    }
+    case UnaryMethod::kOuterProduct: {
+      out << "outer_product";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_method.h b/src/ast/unary_method.h
new file mode 100644
index 0000000..3f719ef
--- /dev/null
+++ b/src/ast/unary_method.h
@@ -0,0 +1,40 @@
+// 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_AST_UNARY_METHOD_H_
+#define SRC_AST_UNARY_METHOD_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The unary methods
+enum class UnaryMethod {
+  kAny = 0,
+  kAll,
+  kIsNan,
+  kIsInf,
+  kIsFinite,
+  kIsNormal,
+  kDot,
+  kOuterProduct
+};
+
+std::ostream& operator<<(std::ostream& out, UnaryMethod mod);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNARY_METHOD_H_
diff --git a/src/ast/unary_method_expression.cc b/src/ast/unary_method_expression.cc
new file mode 100644
index 0000000..058c683
--- /dev/null
+++ b/src/ast/unary_method_expression.cc
@@ -0,0 +1,52 @@
+// 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/ast/unary_method_expression.h"
+
+namespace tint {
+namespace ast {
+
+UnaryMethodExpression::UnaryMethodExpression(
+    UnaryMethod op,
+    std::vector<std::unique_ptr<Expression>> params)
+    : Expression(), op_(op), params_(std::move(params)) {}
+
+UnaryMethodExpression::UnaryMethodExpression(
+    const Source& source,
+    UnaryMethod op,
+    std::vector<std::unique_ptr<Expression>> params)
+    : Expression(source), op_(op), params_(std::move(params)) {}
+
+UnaryMethodExpression::~UnaryMethodExpression() = default;
+
+bool UnaryMethodExpression::IsValid() const {
+  return true;
+}
+
+void UnaryMethodExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+
+  out << "UnaryMethod{" << std::endl;
+  make_indent(out, indent + 2);
+  out << op_ << std::endl;
+  for (const auto& param : params_) {
+    param->to_str(out, indent + 2);
+    out << std::endl;
+  }
+  make_indent(out, indent);
+  out << "}";
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_method_expression.h b/src/ast/unary_method_expression.h
new file mode 100644
index 0000000..806d190
--- /dev/null
+++ b/src/ast/unary_method_expression.h
@@ -0,0 +1,85 @@
+// 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_AST_UNARY_METHOD_EXPRESSION_H_
+#define SRC_AST_UNARY_METHOD_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/unary_method.h"
+
+namespace tint {
+namespace ast {
+
+/// A unary method expression
+class UnaryMethodExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param op the op
+  /// @param params the params
+  UnaryMethodExpression(UnaryMethod op,
+                        std::vector<std::unique_ptr<Expression>> params);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param op the op
+  /// @param params the params
+  UnaryMethodExpression(const Source& source,
+                        UnaryMethod op,
+                        std::vector<std::unique_ptr<Expression>> params);
+  /// Move constructor
+  UnaryMethodExpression(UnaryMethodExpression&&) = default;
+  ~UnaryMethodExpression() override;
+
+  /// Sets the op
+  /// @param op the op
+  void set_op(UnaryMethod op) { op_ = op; }
+  /// @returns the op
+  UnaryMethod op() const { return op_; }
+
+  /// Sets the params
+  /// @param params the parameters
+  void set_params(std::vector<std::unique_ptr<Expression>> params) {
+    params_ = std::move(params);
+  }
+  /// @returns the params
+  const std::vector<std::unique_ptr<Expression>>& params() const {
+    return params_;
+  }
+
+  /// @returns true if this is an as expression
+  bool IsUnaryMethod() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  UnaryMethodExpression(const UnaryMethodExpression&) = delete;
+
+  UnaryMethod op_ = UnaryMethod::kAny;
+  std::vector<std::unique_ptr<Expression>> params_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNARY_METHOD_EXPRESSION_H_
diff --git a/src/ast/unary_op.cc b/src/ast/unary_op.cc
new file mode 100644
index 0000000..5c8bba1
--- /dev/null
+++ b/src/ast/unary_op.cc
@@ -0,0 +1,35 @@
+// 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/ast/unary_op.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, UnaryOp mod) {
+  switch (mod) {
+    case UnaryOp::kNegation: {
+      out << "negation";
+      break;
+    }
+    case UnaryOp::kNot: {
+      out << "not";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_op.h b/src/ast/unary_op.h
new file mode 100644
index 0000000..8a6b9f7
--- /dev/null
+++ b/src/ast/unary_op.h
@@ -0,0 +1,31 @@
+// 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_AST_UNARY_OP_H_
+#define SRC_AST_UNARY_OP_H_
+
+#include <ostream>
+
+namespace tint {
+namespace ast {
+
+/// The unary op
+enum class UnaryOp { kNegation = 0, kNot };
+
+std::ostream& operator<<(std::ostream& out, UnaryOp mod);
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNARY_OP_H_
diff --git a/src/ast/unary_op_expression.cc b/src/ast/unary_op_expression.cc
new file mode 100644
index 0000000..da31e8e
--- /dev/null
+++ b/src/ast/unary_op_expression.cc
@@ -0,0 +1,44 @@
+// 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/ast/unary_op_expression.h"
+
+namespace tint {
+namespace ast {
+
+UnaryOpExpression::UnaryOpExpression(UnaryOp op,
+                                     std::unique_ptr<Expression> expr)
+    : Expression(), op_(op), expr_(std::move(expr)) {}
+
+UnaryOpExpression::UnaryOpExpression(const Source& source,
+                                     UnaryOp op,
+                                     std::unique_ptr<Expression> expr)
+    : Expression(source), op_(op), expr_(std::move(expr)) {}
+
+UnaryOpExpression::~UnaryOpExpression() = default;
+
+bool UnaryOpExpression::IsValid() const {
+  return expr_ != nullptr;
+}
+
+void UnaryOpExpression::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "UnaryOp{" << op_ << std::endl;
+  expr_->to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unary_op_expression.h b/src/ast/unary_op_expression.h
new file mode 100644
index 0000000..b77c185
--- /dev/null
+++ b/src/ast/unary_op_expression.h
@@ -0,0 +1,79 @@
+// 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_AST_UNARY_OP_EXPRESSION_H_
+#define SRC_AST_UNARY_OP_EXPRESSION_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/literal.h"
+#include "src/ast/unary_op.h"
+
+namespace tint {
+namespace ast {
+
+/// A unary op expression
+class UnaryOpExpression : public Expression {
+ public:
+  /// Constructor
+  /// @param op the op
+  /// @param expr the expr
+  UnaryOpExpression(UnaryOp op, std::unique_ptr<Expression> expr);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param op the op
+  /// @param expr the expr
+  UnaryOpExpression(const Source& source,
+                    UnaryOp op,
+                    std::unique_ptr<Expression> expr);
+  /// Move constructor
+  UnaryOpExpression(UnaryOpExpression&&) = default;
+  ~UnaryOpExpression() override;
+
+  /// Sets the op
+  /// @param op the op
+  void set_op(UnaryOp op) { op_ = op; }
+  /// @returns the op
+  UnaryOp op() const { return op_; }
+
+  /// Sets the expr
+  /// @param expr the expression
+  void set_expr(std::unique_ptr<Expression> expr) { expr_ = std::move(expr); }
+  /// @returns the expression
+  Expression* expr() const { return expr_.get(); }
+
+  /// @returns true if this is an as expression
+  bool IsUnaryOp() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  UnaryOpExpression(const UnaryOpExpression&) = delete;
+
+  UnaryOp op_ = UnaryOp::kNegation;
+  std::unique_ptr<Expression> expr_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNARY_OP_EXPRESSION_H_
diff --git a/src/ast/unless_statement.cc b/src/ast/unless_statement.cc
new file mode 100644
index 0000000..7f591b0
--- /dev/null
+++ b/src/ast/unless_statement.cc
@@ -0,0 +1,56 @@
+// 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/ast/unless_statement.h"
+
+namespace tint {
+namespace ast {
+
+UnlessStatement::UnlessStatement(std::unique_ptr<Expression> condition,
+                                 std::vector<std::unique_ptr<Statement>> body)
+    : Statement(), condition_(std::move(condition)), body_(std::move(body)) {}
+
+UnlessStatement::UnlessStatement(const Source& source,
+                                 std::unique_ptr<Expression> condition,
+                                 std::vector<std::unique_ptr<Statement>> body)
+    : Statement(source),
+      condition_(std::move(condition)),
+      body_(std::move(body)) {}
+
+UnlessStatement::~UnlessStatement() = default;
+
+bool UnlessStatement::IsValid() const {
+  return condition_ != nullptr;
+}
+
+void UnlessStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Unless{" << std::endl;
+
+  condition_->to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "{" << std::endl;
+
+  for (const auto& stmt : body_)
+    stmt->to_str(out, indent + 4);
+
+  make_indent(out, indent + 2);
+  out << "}";
+
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/unless_statement.h b/src/ast/unless_statement.h
new file mode 100644
index 0000000..bafbb43
--- /dev/null
+++ b/src/ast/unless_statement.h
@@ -0,0 +1,84 @@
+// 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_AST_UNLESS_STATEMENT_H_
+#define SRC_AST_UNLESS_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+
+namespace tint {
+namespace ast {
+
+/// A unless statement
+class UnlessStatement : public Statement {
+ public:
+  /// Constructor
+  /// @param condition the condition expression
+  /// @param body the body statements
+  UnlessStatement(std::unique_ptr<Expression> condition,
+                  std::vector<std::unique_ptr<Statement>> body);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param condition the condition expression
+  /// @param body the body statements
+  UnlessStatement(const Source& source,
+                  std::unique_ptr<Expression> condition,
+                  std::vector<std::unique_ptr<Statement>> body);
+  /// Move constructor
+  UnlessStatement(UnlessStatement&&) = default;
+  ~UnlessStatement() override;
+
+  /// Sets the condition expression
+  /// @param condition the condition expression
+  void set_condition(std::unique_ptr<Expression> condition) {
+    condition_ = std::move(condition);
+  }
+  /// @returns the condition statements
+  Expression* condition() const { return condition_.get(); }
+
+  /// Sets the body statements
+  /// @param body the body statements
+  void set_body(std::vector<std::unique_ptr<Statement>> body) {
+    body_ = std::move(body);
+  }
+  /// @returns the body statements
+  const std::vector<std::unique_ptr<Statement>>& body() const { return body_; }
+
+  /// @returns true if this is an unless statement
+  bool IsUnless() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  UnlessStatement(const UnlessStatement&) = delete;
+
+  std::unique_ptr<Expression> condition_;
+  std::vector<std::unique_ptr<Statement>> body_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_UNLESS_STATEMENT_H_
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
new file mode 100644
index 0000000..1caa64b
--- /dev/null
+++ b/src/ast/variable.cc
@@ -0,0 +1,74 @@
+// 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/ast/variable.h"
+
+#include <assert.h>
+
+#include "src/ast/decorated_variable.h"
+
+namespace tint {
+namespace ast {
+
+Variable::Variable(const std::string& name, StorageClass sc, type::Type* type)
+    : Node(), name_(name), storage_class_(sc), type_(type) {}
+
+Variable::Variable(const Source& source,
+                   const std::string& name,
+                   StorageClass sc,
+                   type::Type* type)
+    : Node(source), name_(name), storage_class_(sc), type_(type) {}
+
+Variable::~Variable() = default;
+
+DecoratedVariable* Variable::AsDecorated() {
+  assert(IsDecorated());
+  return static_cast<DecoratedVariable*>(this);
+}
+
+bool Variable::IsValid() const {
+  if (name_.length() == 0) {
+    return false;
+  }
+  if (type_ == nullptr) {
+    return false;
+  }
+  return true;
+}
+
+void Variable::info_to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << name_ << std::endl;
+  make_indent(out, indent);
+  out << storage_class_ << std::endl;
+  make_indent(out, indent);
+  out << type_->type_name() << std::endl;
+}
+
+void Variable::to_str(std::ostream& out, size_t indent) const {
+  info_to_str(out, indent);
+
+  if (initializer_ != nullptr) {
+    make_indent(out, indent);
+    out << "{" << std::endl;
+
+    initializer_->to_str(out, indent + 2);
+
+    make_indent(out, indent);
+    out << "}" << std::endl;
+  }
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/variable.h b/src/ast/variable.h
new file mode 100644
index 0000000..db27ed2
--- /dev/null
+++ b/src/ast/variable.h
@@ -0,0 +1,122 @@
+// 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_AST_VARIABLE_H_
+#define SRC_AST_VARIABLE_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/node.h"
+#include "src/ast/storage_class.h"
+#include "src/ast/type/type.h"
+
+namespace tint {
+namespace ast {
+
+class DecoratedVariable;
+
+/// A Variable statement.
+class Variable : public Node {
+ public:
+  /// Create a new empty variable statement
+  Variable() = default;
+  /// Create a variable
+  /// @param name the variables name
+  /// @param sc the variable storage class
+  /// @param type the variables type
+  Variable(const std::string& name, StorageClass sc, type::Type* type);
+  /// Create a variable
+  /// @param source the variable source
+  /// @param name the variables name
+  /// @param sc the variable storage class
+  /// @param type the variables type
+  Variable(const Source& source,
+           const std::string& name,
+           StorageClass sc,
+           type::Type* type);
+  /// Move constructor
+  Variable(Variable&&) = default;
+
+  ~Variable() override;
+
+  /// Sets the variable name
+  /// @param name the name to set
+  void set_name(const std::string& name) { name_ = name; }
+  /// @returns the variable name
+  const std::string& name() { return name_; }
+
+  /// Sets the type of the variable
+  /// @param type the type
+  void set_type(type::Type* type) { type_ = type; }
+  /// @returns the variables type.
+  type::Type* type() const { return type_; }
+
+  /// Sets the storage class
+  /// @param sc the storage class
+  void set_storage_class(StorageClass sc) { storage_class_ = sc; }
+  /// @returns the storage class
+  StorageClass storage_class() const { return storage_class_; }
+
+  /// Sets the initializer
+  /// @param expr the initializer expression
+  void set_initializer(std::unique_ptr<Expression> expr) {
+    initializer_ = std::move(expr);
+  }
+  /// @returns the initializer expression or nullptr if none set
+  Expression* initializer() const { return initializer_.get(); }
+
+  /// Sets if the variable is constant
+  /// @param val the value to be set
+  void set_is_const(bool val) { is_const_ = val; }
+  /// @returns true if this is a constant, false otherwise
+  bool is_const() const { return is_const_; }
+
+  /// @returns true if this is a decorated variable
+  virtual bool IsDecorated() const { return false; }
+
+  /// @returns the expression as a decorated variable
+  DecoratedVariable* AsDecorated();
+
+  /// @returns true if the name and path are both present
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ protected:
+  /// Output information for this variable.
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void info_to_str(std::ostream& out, size_t indent) const;
+
+ private:
+  Variable(const Variable&) = delete;
+
+  bool is_const_ = false;
+  std::string name_;
+  StorageClass storage_class_ = StorageClass::kNone;
+  type::Type* type_ = nullptr;
+  std::unique_ptr<Expression> initializer_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_VARIABLE_H_
diff --git a/src/ast/variable_decoration.cc b/src/ast/variable_decoration.cc
new file mode 100644
index 0000000..2f70268
--- /dev/null
+++ b/src/ast/variable_decoration.cc
@@ -0,0 +1,52 @@
+// 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/ast/variable_decoration.h"
+
+#include <assert.h>
+
+#include "src/ast/binding_decoration.h"
+#include "src/ast/builtin_decoration.h"
+#include "src/ast/location_decoration.h"
+#include "src/ast/set_decoration.h"
+
+namespace tint {
+namespace ast {
+
+VariableDecoration::VariableDecoration() = default;
+
+VariableDecoration::~VariableDecoration() = default;
+
+BindingDecoration* VariableDecoration::AsBinding() {
+  assert(IsBinding());
+  return static_cast<BindingDecoration*>(this);
+}
+
+BuiltinDecoration* VariableDecoration::AsBuiltin() {
+  assert(IsBuiltin());
+  return static_cast<BuiltinDecoration*>(this);
+}
+
+LocationDecoration* VariableDecoration::AsLocation() {
+  assert(IsLocation());
+  return static_cast<LocationDecoration*>(this);
+}
+
+SetDecoration* VariableDecoration::AsSet() {
+  assert(IsSet());
+  return static_cast<SetDecoration*>(this);
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/variable_decoration.h b/src/ast/variable_decoration.h
new file mode 100644
index 0000000..2e7bd04
--- /dev/null
+++ b/src/ast/variable_decoration.h
@@ -0,0 +1,63 @@
+// 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_AST_VARIABLE_DECORATION_H_
+#define SRC_AST_VARIABLE_DECORATION_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint {
+namespace ast {
+
+class BindingDecoration;
+class BuiltinDecoration;
+class LocationDecoration;
+class SetDecoration;
+
+/// A decoration attached to a variable
+class VariableDecoration {
+ public:
+  virtual ~VariableDecoration();
+
+  /// @returns true if this is a binding decoration
+  virtual bool IsBinding() const { return false; }
+  /// @returns true if this is a builtin decoration
+  virtual bool IsBuiltin() const { return false; }
+  /// @returns true if this is a location decoration
+  virtual bool IsLocation() const { return false; }
+  /// @returns true if this is a set decoration
+  virtual bool IsSet() const { return false; }
+
+  /// @returns the decoration as a binding decoration
+  BindingDecoration* AsBinding();
+  /// @returns the decoration as a builtin decoration
+  BuiltinDecoration* AsBuiltin();
+  /// @returns the decoration as a location decoration
+  LocationDecoration* AsLocation();
+  /// @returns the decoration as a set decoration
+  SetDecoration* AsSet();
+
+  /// Outputs the variable decoration to the given stream
+  /// @param out the stream to output too
+  virtual void to_str(std::ostream& out) const = 0;
+
+ protected:
+  VariableDecoration();
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_VARIABLE_DECORATION_H_
diff --git a/src/ast/variable_statement.cc b/src/ast/variable_statement.cc
new file mode 100644
index 0000000..a195575
--- /dev/null
+++ b/src/ast/variable_statement.cc
@@ -0,0 +1,42 @@
+// 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/ast/variable_statement.h"
+
+namespace tint {
+namespace ast {
+
+VariableStatement::VariableStatement(std::unique_ptr<Variable> variable)
+    : Statement(), variable_(std::move(variable)) {}
+
+VariableStatement::VariableStatement(const Source& source,
+                                     std::unique_ptr<Variable> variable)
+    : Statement(source), variable_(std::move(variable)) {}
+
+VariableStatement::~VariableStatement() = default;
+
+bool VariableStatement::IsValid() const {
+  return variable_ != nullptr;
+}
+
+void VariableStatement::to_str(std::ostream& out, size_t indent) const {
+  make_indent(out, indent);
+  out << "Variable{" << std::endl;
+  variable_->to_str(out, indent + 2);
+  make_indent(out, indent);
+  out << "}" << std::endl;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/variable_statement.h b/src/ast/variable_statement.h
new file mode 100644
index 0000000..17e0742
--- /dev/null
+++ b/src/ast/variable_statement.h
@@ -0,0 +1,70 @@
+// 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_AST_VARIABLE_STATEMENT_H_
+#define SRC_AST_VARIABLE_STATEMENT_H_
+
+#include <memory>
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/statement.h"
+#include "src/ast/variable.h"
+
+namespace tint {
+namespace ast {
+
+/// A variable statement
+class VariableStatement : public Statement {
+ public:
+  /// Constructor
+  /// @param variable the variable
+  explicit VariableStatement(std::unique_ptr<Variable> variable);
+  /// Constructor
+  /// @param source the initializer source
+  /// @param variable the variable
+  VariableStatement(const Source& source, std::unique_ptr<Variable> variable);
+  /// Move constructor
+  VariableStatement(VariableStatement&&) = default;
+  ~VariableStatement() override;
+
+  /// Sets the variable
+  /// @param variable the variable to set
+  void set_variable(std::unique_ptr<Variable> variable) {
+    variable_ = std::move(variable);
+  }
+  /// @returns the variable
+  Variable* variable() const { return variable_.get(); }
+
+  /// @returns true if this is an variable statement
+  bool IsVariable() const override { return true; }
+
+  /// @returns true if the node is valid
+  bool IsValid() const override;
+
+  /// Writes a representation of the node to the output stream
+  /// @param out the stream to write to
+  /// @param indent number of spaces to indent the node when writing
+  void to_str(std::ostream& out, size_t indent) const override;
+
+ private:
+  VariableStatement(const VariableStatement&) = delete;
+
+  std::unique_ptr<Variable> variable_;
+};
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_VARIABLE_STATEMENT_H_
diff --git a/src/ast/variable_test.cc b/src/ast/variable_test.cc
new file mode 100644
index 0000000..0f4f59b
--- /dev/null
+++ b/src/ast/variable_test.cc
@@ -0,0 +1,100 @@
+// 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/ast/variable.h"
+
+#include "gtest/gtest.h"
+#include "src/ast/type/f32_type.h"
+#include "src/ast/type/i32_type.h"
+
+namespace tint {
+namespace ast {
+
+using VariableTest = testing::Test;
+
+TEST_F(VariableTest, Creation) {
+  type::I32Type t;
+  Variable v("my_var", StorageClass::kFunction, &t);
+
+  EXPECT_EQ(v.name(), "my_var");
+  EXPECT_EQ(v.storage_class(), StorageClass::kFunction);
+  EXPECT_EQ(v.type(), &t);
+  EXPECT_EQ(v.line(), 0);
+  EXPECT_EQ(v.column(), 0);
+}
+
+TEST_F(VariableTest, CreationWithSource) {
+  Source s{27, 4};
+  type::F32Type t;
+  Variable v(s, "i", StorageClass::kPrivate, &t);
+
+  EXPECT_EQ(v.name(), "i");
+  EXPECT_EQ(v.storage_class(), StorageClass::kPrivate);
+  EXPECT_EQ(v.type(), &t);
+  EXPECT_EQ(v.line(), 27);
+  EXPECT_EQ(v.column(), 4);
+}
+
+TEST_F(VariableTest, CreationEmpty) {
+  Source s{27, 4};
+  Variable v;
+  v.set_source(s);
+  v.set_storage_class(StorageClass::kWorkgroup);
+  v.set_name("a_var");
+
+  type::I32Type t;
+  v.set_type(&t);
+
+  EXPECT_EQ(v.name(), "a_var");
+  EXPECT_EQ(v.storage_class(), StorageClass::kWorkgroup);
+  EXPECT_EQ(v.type(), &t);
+  EXPECT_EQ(v.line(), 27);
+  EXPECT_EQ(v.column(), 4);
+}
+
+TEST_F(VariableTest, IsValid) {
+  type::I32Type t;
+  Variable v{"my_var", StorageClass::kNone, &t};
+  EXPECT_TRUE(v.IsValid());
+}
+
+TEST_F(VariableTest, IsValid_MissinName) {
+  type::I32Type t;
+  Variable v{"", StorageClass::kNone, &t};
+  EXPECT_FALSE(v.IsValid());
+}
+
+TEST_F(VariableTest, IsValid_MissingType) {
+  Variable v{"x", StorageClass::kNone, nullptr};
+  EXPECT_FALSE(v.IsValid());
+}
+
+TEST_F(VariableTest, IsValid_MissingBoth) {
+  Variable v;
+  EXPECT_FALSE(v.IsValid());
+}
+
+TEST_F(VariableTest, to_str) {
+  type::F32Type t;
+  Variable v{"my_var", StorageClass::kFunction, &t};
+  std::ostringstream out;
+  v.to_str(out, 0);
+  EXPECT_EQ(out.str(), R"(my_var
+function
+__f32
+)");
+}
+
+}  // namespace ast
+}  // namespace tint