Prechádzať zdrojové kódy

Refactor output to be more streaming-focused. (#666)

- Switch code to llvm::raw_ostream as part of standardizing output forms.
    - Preferring llvm::raw_ostream over std::ostream because other tooling code should be expected to rely on llvm more closely, and an overall preference towards library consistency.
    - There are a couple spots in syntax/ that still use std streams, but I'd prefer to take a separate PR to see how best to address those.
    - std::boolalpha doesn't work with llvm, so I've implemented equivalent in a couple places (not enough that it felt like worth making a helper function).
- Implement Print(ostream) as consistently as we can, as an instance member.
    - This facilitates the use of the common/ostream.h template to provide operators.
    - Preferring this approach so that Print is easily accessible via gdb, per suggestion on #executable-semantics.
- Switch code currently calling `type->Print(ostream)` to instead do `ostream << *type`.
- Remove the unused `PrintTypeEnv`, nothing used it and the declaration didn't match the definition.
Jon Meow 4 rokov pred
rodič
commit
8fccecadeb
31 zmenil súbory, kde vykonal 391 pridanie a 458 odobranie
  1. 8 0
      common/BUILD
  2. 23 0
      common/ostream.h
  3. 14 3
      executable_semantics/ast/BUILD
  4. 10 17
      executable_semantics/ast/declaration.cpp
  5. 2 1
      executable_semantics/ast/declaration.h
  6. 50 69
      executable_semantics/ast/expression.cpp
  7. 4 2
      executable_semantics/ast/expression.h
  8. 6 11
      executable_semantics/ast/function_definition.cpp
  9. 3 2
      executable_semantics/ast/function_definition.h
  10. 2 6
      executable_semantics/ast/member.cpp
  11. 2 1
      executable_semantics/ast/member.h
  12. 48 66
      executable_semantics/ast/statement.cpp
  13. 3 2
      executable_semantics/ast/statement.h
  14. 8 0
      executable_semantics/interpreter/BUILD
  15. 8 9
      executable_semantics/interpreter/action.cpp
  16. 3 3
      executable_semantics/interpreter/action.h
  17. 3 4
      executable_semantics/interpreter/address.h
  18. 4 5
      executable_semantics/interpreter/field_path.h
  19. 3 4
      executable_semantics/interpreter/frame.cpp
  20. 3 2
      executable_semantics/interpreter/frame.h
  21. 7 9
      executable_semantics/interpreter/heap.cpp
  22. 5 5
      executable_semantics/interpreter/heap.h
  23. 62 81
      executable_semantics/interpreter/interpreter.cpp
  24. 2 1
      executable_semantics/interpreter/interpreter.h
  25. 57 86
      executable_semantics/interpreter/typecheck.cpp
  26. 1 4
      executable_semantics/interpreter/typecheck.h
  27. 33 53
      executable_semantics/interpreter/value.cpp
  28. 3 2
      executable_semantics/interpreter/value.h
  29. 4 0
      executable_semantics/main.cpp
  30. 1 0
      executable_semantics/syntax/BUILD
  31. 9 10
      executable_semantics/syntax/syntax_helpers.cpp

+ 8 - 0
common/BUILD

@@ -36,3 +36,11 @@ cc_test(
         "@llvm-project//llvm:gtest_main",
     ],
 )
+
+cc_library(
+    name = "ostream",
+    hdrs = ["ostream.h"],
+    deps = [
+        "@llvm-project//llvm:Support",
+    ],
+)

+ 23 - 0
common/ostream.h

@@ -0,0 +1,23 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef COMMON_OSTREAM_H_
+#define COMMON_OSTREAM_H_
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace Carbon {
+
+// Support ostream << for types which implement:
+//   void Print(llvm::raw_ostream& out) const;
+template <typename T, typename std::enable_if<std::is_member_function_pointer<
+                          decltype(&T::Print)>::value>::type* = nullptr>
+auto operator<<(llvm::raw_ostream& out, const T& obj) -> llvm::raw_ostream& {
+  obj.Print(out);
+  return out;
+}
+
+}  // namespace Carbon
+
+#endif  // COMMON_OSTREAM_H_

+ 14 - 3
executable_semantics/ast/BUILD

@@ -17,6 +17,7 @@ cc_library(
         ":function_definition",
         ":member",
         ":struct_definition",
+        "//common:ostream",
         "//executable_semantics/interpreter:address",
         "//executable_semantics/interpreter:containers",
     ],
@@ -26,7 +27,10 @@ cc_library(
     name = "expression",
     srcs = ["expression.cpp"],
     hdrs = ["expression.h"],
-    deps = ["//common:indirect_value"],
+    deps = [
+        "//common:indirect_value",
+        "//common:ostream",
+    ],
 )
 
 cc_library(
@@ -43,7 +47,10 @@ cc_library(
     name = "member",
     srcs = ["member.cpp"],
     hdrs = ["member.h"],
-    deps = [":expression"],
+    deps = [
+        ":expression",
+        "//common:ostream",
+    ],
 )
 
 cc_library(
@@ -53,11 +60,15 @@ cc_library(
     deps = [
         ":expression",
         "//common:check",
+        "//common:ostream",
     ],
 )
 
 cc_library(
     name = "struct_definition",
     hdrs = ["struct_definition.h"],
-    deps = [":member"],
+    deps = [
+        ":member",
+        "//common:ostream",
+    ],
 )

+ 10 - 17
executable_semantics/ast/declaration.cpp

@@ -4,8 +4,6 @@
 
 #include "executable_semantics/ast/declaration.h"
 
-#include <iostream>
-
 namespace Carbon {
 
 auto Declaration::MakeFunctionDeclaration(FunctionDefinition definition)
@@ -65,41 +63,36 @@ auto Declaration::GetVariableDeclaration() const -> const VariableDeclaration& {
   return std::get<VariableDeclaration>(value);
 }
 
-void Declaration::Print() const {
+void Declaration::Print(llvm::raw_ostream& out) const {
   switch (tag()) {
     case DeclarationKind::FunctionDeclaration:
-      GetFunctionDeclaration().definition.Print();
+      out << GetFunctionDeclaration().definition;
       break;
 
     case DeclarationKind::StructDeclaration: {
       const StructDefinition& struct_def = GetStructDeclaration().definition;
-      std::cout << "struct " << struct_def.name << " {" << std::endl;
+      out << "struct " << struct_def.name << " {\n";
       for (Member* m : struct_def.members) {
-        m->Print();
+        out << *m;
       }
-      std::cout << "}" << std::endl;
+      out << "}\n";
       break;
     }
 
     case DeclarationKind::ChoiceDeclaration: {
       const auto& choice = GetChoiceDeclaration();
-      std::cout << "choice " << choice.name << " {" << std::endl;
+      out << "choice " << choice.name << " {\n";
       for (const auto& [name, signature] : choice.alternatives) {
-        std::cout << "alt " << name << " ";
-        PrintExp(signature);
-        std::cout << ";" << std::endl;
+        out << "alt " << name << " " << *signature << ";\n";
       }
-      std::cout << "}" << std::endl;
+      out << "}\n";
       break;
     }
 
     case DeclarationKind::VariableDeclaration: {
       const auto& var = GetVariableDeclaration();
-      std::cout << "var ";
-      PrintExp(var.type);
-      std::cout << " : " << var.name << " = ";
-      PrintExp(var.initializer);
-      std::cout << std::endl;
+      out << "var " << *var.type << " : " << var.name << " = "
+          << *var.initializer << "\n";
       break;
     }
   }

+ 2 - 1
executable_semantics/ast/declaration.h

@@ -8,6 +8,7 @@
 #include <list>
 #include <string>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/function_definition.h"
 #include "executable_semantics/ast/member.h"
 #include "executable_semantics/ast/struct_definition.h"
@@ -82,7 +83,7 @@ class Declaration {
   auto GetChoiceDeclaration() const -> const ChoiceDeclaration&;
   auto GetVariableDeclaration() const -> const VariableDeclaration&;
 
-  void Print() const;
+  void Print(llvm::raw_ostream& out) const;
 
   inline auto tag() const -> DeclarationKind {
     return std::visit([](const auto& t) { return t.Kind; }, value);

+ 50 - 69
executable_semantics/ast/expression.cpp

@@ -4,8 +4,6 @@
 
 #include "executable_semantics/ast/expression.h"
 
-#include <iostream>
-
 namespace Carbon {
 
 auto Expression::GetIdentifierExpression() const
@@ -168,9 +166,8 @@ auto Expression::MakeTupleLiteral(int line_num,
   for (auto& arg : args) {
     if (arg.name == "") {
       if (seen_named_member) {
-        std::cerr << line_num
-                  << ": positional members must come before named members"
-                  << std::endl;
+        llvm::errs() << line_num
+                     << ": positional members must come before named members\n";
         exit(-1);
       }
       arg.name = std::to_string(i);
@@ -191,138 +188,122 @@ auto Expression::MakeIndexExpression(int line_num, const Expression* exp,
   return e;
 }
 
-static void PrintOp(Operator op) {
+static void PrintOp(llvm::raw_ostream& out, Operator op) {
   switch (op) {
     case Operator::Add:
-      std::cout << "+";
+      out << "+";
       break;
     case Operator::Neg:
     case Operator::Sub:
-      std::cout << "-";
+      out << "-";
       break;
     case Operator::Mul:
     case Operator::Deref:
     case Operator::Ptr:
-      std::cout << "*";
+      out << "*";
       break;
     case Operator::Not:
-      std::cout << "not";
+      out << "not";
       break;
     case Operator::And:
-      std::cout << "and";
+      out << "and";
       break;
     case Operator::Or:
-      std::cout << "or";
+      out << "or";
       break;
     case Operator::Eq:
-      std::cout << "==";
+      out << "==";
       break;
   }
 }
 
-static void PrintFields(const std::vector<FieldInitializer>& fields) {
+static void PrintFields(llvm::raw_ostream& out,
+                        const std::vector<FieldInitializer>& fields) {
   int i = 0;
   for (auto iter = fields.begin(); iter != fields.end(); ++iter, ++i) {
     if (i != 0) {
-      std::cout << ", ";
+      out << ", ";
     }
-    std::cout << iter->name << " = ";
-    PrintExp(iter->expression);
+    out << iter->name << " = " << *iter->expression;
   }
 }
 
-void PrintExp(const Expression* e) {
-  switch (e->tag()) {
+void Expression::Print(llvm::raw_ostream& out) const {
+  switch (tag()) {
     case ExpressionKind::IndexExpression:
-      PrintExp(e->GetIndexExpression().aggregate);
-      std::cout << "[";
-      PrintExp(e->GetIndexExpression().offset);
-      std::cout << "]";
+      out << *GetIndexExpression().aggregate << "["
+          << *GetIndexExpression().offset << "]";
       break;
     case ExpressionKind::FieldAccessExpression:
-      PrintExp(e->GetFieldAccessExpression().aggregate);
-      std::cout << ".";
-      std::cout << e->GetFieldAccessExpression().field;
+      out << *GetFieldAccessExpression().aggregate << "."
+          << GetFieldAccessExpression().field;
       break;
     case ExpressionKind::TupleLiteral:
-      std::cout << "(";
-      PrintFields(e->GetTupleLiteral().fields);
-      std::cout << ")";
+      out << "(";
+      PrintFields(out, GetTupleLiteral().fields);
+      out << ")";
       break;
     case ExpressionKind::IntLiteral:
-      std::cout << e->GetIntLiteral();
+      out << GetIntLiteral();
       break;
     case ExpressionKind::BoolLiteral:
-      std::cout << std::boolalpha;
-      std::cout << e->GetBoolLiteral();
+      out << (GetBoolLiteral() ? "true" : "false");
       break;
     case ExpressionKind::PrimitiveOperatorExpression: {
-      std::cout << "(";
-      PrimitiveOperatorExpression op = e->GetPrimitiveOperatorExpression();
+      out << "(";
+      PrimitiveOperatorExpression op = GetPrimitiveOperatorExpression();
       if (op.arguments.size() == 0) {
-        PrintOp(op.op);
+        PrintOp(out, op.op);
       } else if (op.arguments.size() == 1) {
-        PrintOp(op.op);
-        std::cout << " ";
-        auto iter = op.arguments.begin();
-        PrintExp(*iter);
+        PrintOp(out, op.op);
+        out << " " << *op.arguments[0];
       } else if (op.arguments.size() == 2) {
-        auto iter = op.arguments.begin();
-        PrintExp(*iter);
-        std::cout << " ";
-        PrintOp(op.op);
-        std::cout << " ";
-        ++iter;
-        PrintExp(*iter);
+        out << *op.arguments[0] << " ";
+        PrintOp(out, op.op);
+        out << " " << *op.arguments[1];
       }
-      std::cout << ")";
+      out << ")";
       break;
     }
     case ExpressionKind::IdentifierExpression:
-      std::cout << e->GetIdentifierExpression().name;
+      out << GetIdentifierExpression().name;
       break;
     case ExpressionKind::BindingExpression: {
-      const BindingExpression& binding = e->GetBindingExpression();
+      const BindingExpression& binding = GetBindingExpression();
       if (binding.name.has_value()) {
-        std::cout << *binding.name;
+        out << *binding.name;
       } else {
-        std::cout << "_";
+        out << "_";
       }
-      std::cout << ": ";
-      PrintExp(e->GetBindingExpression().type);
+      out << ": " << *binding.type;
       break;
     }
     case ExpressionKind::CallExpression:
-      PrintExp(e->GetCallExpression().function);
-      if (e->GetCallExpression().argument->tag() ==
-          ExpressionKind::TupleLiteral) {
-        PrintExp(e->GetCallExpression().argument);
+      out << *GetCallExpression().function;
+      if (GetCallExpression().argument->tag() == ExpressionKind::TupleLiteral) {
+        out << *GetCallExpression().argument;
       } else {
-        std::cout << "(";
-        PrintExp(e->GetCallExpression().argument);
-        std::cout << ")";
+        out << "(" << *GetCallExpression().argument << ")";
       }
       break;
     case ExpressionKind::BoolTypeLiteral:
-      std::cout << "Bool";
+      out << "Bool";
       break;
     case ExpressionKind::IntTypeLiteral:
-      std::cout << "Int";
+      out << "Int";
       break;
     case ExpressionKind::TypeTypeLiteral:
-      std::cout << "Type";
+      out << "Type";
       break;
     case ExpressionKind::AutoTypeLiteral:
-      std::cout << "auto";
+      out << "auto";
       break;
     case ExpressionKind::ContinuationTypeLiteral:
-      std::cout << "Continuation";
+      out << "Continuation";
       break;
     case ExpressionKind::FunctionTypeLiteral:
-      std::cout << "fn ";
-      PrintExp(e->GetFunctionTypeLiteral().parameter);
-      std::cout << " -> ";
-      PrintExp(e->GetFunctionTypeLiteral().return_type);
+      out << "fn " << *GetFunctionTypeLiteral().parameter << " -> "
+          << *GetFunctionTypeLiteral().return_type;
       break;
   }
 }

+ 4 - 2
executable_semantics/ast/expression.h

@@ -10,6 +10,8 @@
 #include <variant>
 #include <vector>
 
+#include "common/ostream.h"
+
 namespace Carbon {
 
 struct Expression;
@@ -176,6 +178,8 @@ struct Expression {
   auto GetCallExpression() const -> const CallExpression&;
   auto GetFunctionTypeLiteral() const -> const FunctionTypeLiteral&;
 
+  void Print(llvm::raw_ostream& out) const;
+
   inline auto tag() const -> ExpressionKind {
     return std::visit([](const auto& t) { return t.Kind; }, value);
   }
@@ -191,8 +195,6 @@ struct Expression {
       value;
 };
 
-void PrintExp(const Expression* exp);
-
 }  // namespace Carbon
 
 #endif  // EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_

+ 6 - 11
executable_semantics/ast/function_definition.cpp

@@ -4,21 +4,16 @@
 
 #include "executable_semantics/ast/function_definition.h"
 
-#include <iostream>
-
 namespace Carbon {
 
-void FunctionDefinition::PrintDepth(int depth) const {
-  std::cout << "fn " << name << " ";
-  PrintExp(param_pattern);
-  std::cout << " -> ";
-  PrintExp(return_type);
+void FunctionDefinition::PrintDepth(int depth, llvm::raw_ostream& out) const {
+  out << "fn " << name << " " << *param_pattern << " -> " << *return_type;
   if (body) {
-    std::cout << " {" << std::endl;
-    PrintStatement(body, depth);
-    std::cout << std::endl << "}" << std::endl;
+    out << " {\n";
+    body->PrintDepth(depth, out);
+    out << "\n}\n";
   } else {
-    std::cout << ";" << std::endl;
+    out << ";\n";
   }
 }
 

+ 3 - 2
executable_semantics/ast/function_definition.h

@@ -5,6 +5,7 @@
 #ifndef EXECUTABLE_SEMANTICS_AST_FUNCTION_DEFINITION_H_
 #define EXECUTABLE_SEMANTICS_AST_FUNCTION_DEFINITION_H_
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/expression.h"
 #include "executable_semantics/ast/statement.h"
 
@@ -21,8 +22,8 @@ struct FunctionDefinition {
         return_type(return_type),
         body(body) {}
 
-  void Print() const { PrintDepth(-1); }
-  void PrintDepth(int depth) const;
+  void Print(llvm::raw_ostream& out) const { PrintDepth(-1, out); }
+  void PrintDepth(int depth, llvm::raw_ostream& out) const;
 
   int line_num;
   std::string name;

+ 2 - 6
executable_semantics/ast/member.cpp

@@ -4,8 +4,6 @@
 
 #include "executable_semantics/ast/member.h"
 
-#include <iostream>
-
 namespace Carbon {
 
 auto Member::MakeFieldMember(int line_num, std::string name,
@@ -20,13 +18,11 @@ auto Member::GetFieldMember() const -> const FieldMember& {
   return std::get<FieldMember>(value);
 }
 
-void Member::Print() {
+void Member::Print(llvm::raw_ostream& out) const {
   switch (tag()) {
     case MemberKind::FieldMember:
       const auto& field = GetFieldMember();
-      std::cout << "var " << field.name << " : ";
-      PrintExp(field.type);
-      std::cout << ";" << std::endl;
+      out << "var " << field.name << " : " << *field.type << ";\n";
       break;
   }
 }

+ 2 - 1
executable_semantics/ast/member.h

@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/expression.h"
 
 namespace Carbon {
@@ -25,7 +26,7 @@ struct Member {
 
   auto GetFieldMember() const -> const FieldMember&;
 
-  void Print();
+  void Print(llvm::raw_ostream& out) const;
 
   inline auto tag() const -> MemberKind {
     return std::visit([](const auto& t) { return t.Kind; }, value);

+ 48 - 66
executable_semantics/ast/statement.cpp

@@ -4,8 +4,6 @@
 
 #include "executable_semantics/ast/statement.h"
 
-#include <iostream>
-
 #include "common/check.h"
 
 namespace Carbon {
@@ -182,117 +180,101 @@ auto Statement::MakeAwait(int line_num) -> const Statement* {
   return s;
 }
 
-void PrintStatement(const Statement* s, int depth) {
-  if (!s) {
-    return;
-  }
+void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
   if (depth == 0) {
-    std::cout << " ... ";
+    out << " ... ";
     return;
   }
-  switch (s->tag()) {
+  switch (tag()) {
     case StatementKind::Match:
-      std::cout << "match (";
-      PrintExp(s->GetMatch().exp);
-      std::cout << ") {";
+      out << "match (" << *GetMatch().exp << ") {";
       if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
-        for (auto& clause : *s->GetMatch().clauses) {
-          std::cout << "case ";
-          PrintExp(clause.first);
-          std::cout << " =>" << std::endl;
-          PrintStatement(clause.second, depth - 1);
-          std::cout << std::endl;
+        out << "\n";
+        for (auto& clause : *GetMatch().clauses) {
+          out << "case " << *clause.first << " =>\n";
+          clause.second->PrintDepth(depth - 1, out);
+          out << "\n";
         }
       } else {
-        std::cout << "...";
+        out << "...";
       }
-      std::cout << "}";
+      out << "}";
       break;
     case StatementKind::While:
-      std::cout << "while (";
-      PrintExp(s->GetWhile().cond);
-      std::cout << ")" << std::endl;
-      PrintStatement(s->GetWhile().body, depth - 1);
+      out << "while (" << *GetWhile().cond << ")\n";
+      GetWhile().body->PrintDepth(depth - 1, out);
       break;
     case StatementKind::Break:
-      std::cout << "break;";
+      out << "break;";
       break;
     case StatementKind::Continue:
-      std::cout << "continue;";
+      out << "continue;";
       break;
     case StatementKind::VariableDefinition:
-      std::cout << "var ";
-      PrintExp(s->GetVariableDefinition().pat);
-      std::cout << " = ";
-      PrintExp(s->GetVariableDefinition().init);
-      std::cout << ";";
+      out << "var " << *GetVariableDefinition().pat << " = "
+          << *GetVariableDefinition().init << ";";
       break;
     case StatementKind::ExpressionStatement:
-      PrintExp(s->GetExpressionStatement().exp);
-      std::cout << ";";
+      out << *GetExpressionStatement().exp << ";";
       break;
     case StatementKind::Assign:
-      PrintExp(s->GetAssign().lhs);
-      std::cout << " = ";
-      PrintExp(s->GetAssign().rhs);
-      std::cout << ";";
+      out << *GetAssign().lhs << " = " << *GetAssign().rhs << ";";
       break;
     case StatementKind::If:
-      std::cout << "if (";
-      PrintExp(s->GetIf().cond);
-      std::cout << ")" << std::endl;
-      PrintStatement(s->GetIf().then_stmt, depth - 1);
-      std::cout << std::endl << "else" << std::endl;
-      PrintStatement(s->GetIf().else_stmt, depth - 1);
+      out << "if (" << *GetIf().cond << ")\n";
+      GetIf().then_stmt->PrintDepth(depth - 1, out);
+      if (GetIf().else_stmt) {
+        out << "\nelse\n";
+        GetIf().else_stmt->PrintDepth(depth - 1, out);
+      }
       break;
     case StatementKind::Return:
-      std::cout << "return ";
-      PrintExp(s->GetReturn().exp);
-      std::cout << ";";
+      out << "return " << *GetReturn().exp << ";";
       break;
     case StatementKind::Sequence:
-      PrintStatement(s->GetSequence().stmt, depth);
+      GetSequence().stmt->PrintDepth(depth, out);
       if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
+        out << "\n";
       } else {
-        std::cout << " ";
+        out << " ";
+      }
+      if (GetSequence().next) {
+        GetSequence().next->PrintDepth(depth - 1, out);
       }
-      PrintStatement(s->GetSequence().next, depth - 1);
       break;
     case StatementKind::Block:
-      std::cout << "{";
+      out << "{";
       if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
+        out << "\n";
       }
-      PrintStatement(s->GetBlock().stmt, depth);
-      if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
+      if (GetBlock().stmt) {
+        GetBlock().stmt->PrintDepth(depth, out);
+        if (depth < 0 || depth > 1) {
+          out << "\n";
+        }
       }
-      std::cout << "}";
+      out << "}";
       if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
+        out << "\n";
       }
       break;
     case StatementKind::Continuation:
-      std::cout << "continuation " << s->GetContinuation().continuation_variable
-                << " ";
+      out << "continuation " << GetContinuation().continuation_variable << " ";
       if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
+        out << "\n";
       }
-      PrintStatement(s->GetContinuation().body, depth - 1);
+      GetContinuation().body->PrintDepth(depth - 1, out);
       if (depth < 0 || depth > 1) {
-        std::cout << std::endl;
+        out << "\n";
       }
       break;
     case StatementKind::Run:
-      std::cout << "run ";
-      PrintExp(s->GetRun().argument);
-      std::cout << ";";
+      out << "run " << *GetRun().argument << ";";
       break;
     case StatementKind::Await:
-      std::cout << "await;";
+      out << "await;";
       break;
   }
 }
+
 }  // namespace Carbon

+ 3 - 2
executable_semantics/ast/statement.h

@@ -7,6 +7,7 @@
 
 #include <list>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/expression.h"
 
 namespace Carbon {
@@ -162,6 +163,8 @@ struct Statement {
   auto GetRun() const -> const Run&;
   auto GetAwait() const -> const Await&;
 
+  void PrintDepth(int depth, llvm::raw_ostream& out) const;
+
   inline auto tag() const -> StatementKind {
     return std::visit([](const auto& t) { return t.Kind; }, value);
   }
@@ -175,8 +178,6 @@ struct Statement {
       value;
 };
 
-void PrintStatement(const Statement*, int);
-
 }  // namespace Carbon
 
 #endif  // EXECUTABLE_SEMANTICS_AST_STATEMENT_H_

+ 8 - 0
executable_semantics/interpreter/BUILD

@@ -13,6 +13,7 @@ cc_library(
     deps = [
         ":containers",
         ":value",
+        "//common:ostream",
         "//executable_semantics/ast:expression",
         "//executable_semantics/ast:function_definition",
         "//executable_semantics/ast:statement",
@@ -24,6 +25,7 @@ cc_library(
     hdrs = ["address.h"],
     deps = [
         ":field_path",
+        "//common:ostream",
     ],
 )
 
@@ -42,6 +44,7 @@ cc_library(
 cc_library(
     name = "field_path",
     hdrs = ["field_path.h"],
+    deps = ["//common:ostream"],
 )
 
 cc_library(
@@ -52,6 +55,7 @@ cc_library(
         ":action",
         ":address",
         ":containers",
+        "//common:ostream",
     ],
 )
 
@@ -62,6 +66,7 @@ cc_library(
     deps = [
         ":address",
         ":value",
+        "//common:ostream",
     ],
 )
 
@@ -81,6 +86,7 @@ cc_library(
         ":heap",
         ":value",
         "//common:check",
+        "//common:ostream",
         "//executable_semantics:tracing_flag",
         "//executable_semantics/ast:declaration",
         "//executable_semantics/ast:expression",
@@ -95,6 +101,7 @@ cc_library(
     deps = [
         ":containers",
         ":interpreter",
+        "//common:ostream",
         "//executable_semantics:tracing_flag",
         "//executable_semantics/ast:expression",
         "//executable_semantics/ast:function_definition",
@@ -110,6 +117,7 @@ cc_library(
         ":address",
         ":containers",
         ":field_path",
+        "//common:ostream",
         "//executable_semantics/ast:statement",
     ],
 )

+ 8 - 9
executable_semantics/interpreter/action.cpp

@@ -4,7 +4,6 @@
 
 #include "executable_semantics/interpreter/action.h"
 
-#include <iostream>
 #include <iterator>
 #include <map>
 #include <optional>
@@ -57,19 +56,19 @@ auto Action::GetValAction() const -> const ValAction& {
   return std::get<ValAction>(value);
 }
 
-void Action::Print(std::ostream& out) {
+void Action::Print(llvm::raw_ostream& out) const {
   switch (tag()) {
     case ActionKind::LValAction:
-      PrintExp(GetLValAction().exp);
+      out << *GetLValAction().exp;
       break;
     case ActionKind::ExpressionAction:
-      PrintExp(GetExpressionAction().exp);
+      out << *GetExpressionAction().exp;
       break;
     case ActionKind::StatementAction:
-      PrintStatement(GetStatementAction().stmt, 1);
+      GetStatementAction().stmt->PrintDepth(1, out);
       break;
     case ActionKind::ValAction:
-      PrintValue(GetValAction().val, out);
+      out << *GetValAction().val;
       break;
   }
   out << "<" << pos << ">";
@@ -77,7 +76,7 @@ void Action::Print(std::ostream& out) {
     out << "(";
     for (auto& result : results) {
       if (result) {
-        PrintValue(result, out);
+        out << *result;
       }
       out << ",";
     }
@@ -85,9 +84,9 @@ void Action::Print(std::ostream& out) {
   }
 }
 
-void Action::PrintList(Stack<Action*> ls, std::ostream& out) {
+void Action::PrintList(Stack<Action*> ls, llvm::raw_ostream& out) {
   if (!ls.IsEmpty()) {
-    ls.Pop()->Print(out);
+    out << *ls.Pop();
     if (!ls.IsEmpty()) {
       out << " :: ";
       PrintList(ls, out);

+ 3 - 3
executable_semantics/interpreter/action.h

@@ -5,9 +5,9 @@
 #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_
 #define EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_
 
-#include <iostream>
 #include <vector>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/expression.h"
 #include "executable_semantics/ast/statement.h"
 #include "executable_semantics/interpreter/stack.h"
@@ -48,14 +48,14 @@ struct Action {
   static auto MakeStatementAction(const Statement* s) -> Action*;
   static auto MakeValAction(const Value* v) -> Action*;
 
-  static void PrintList(Stack<Action*> ls, std::ostream& out);
+  static void PrintList(Stack<Action*> ls, llvm::raw_ostream& out);
 
   auto GetLValAction() const -> const LValAction&;
   auto GetExpressionAction() const -> const ExpressionAction&;
   auto GetStatementAction() const -> const StatementAction&;
   auto GetValAction() const -> const ValAction&;
 
-  void Print(std::ostream& out);
+  void Print(llvm::raw_ostream& out) const;
 
   inline auto tag() const -> ActionKind {
     return std::visit([](const auto& t) { return t.Kind; }, value);

+ 3 - 4
executable_semantics/interpreter/address.h

@@ -6,10 +6,10 @@
 #define EXECUTABLE_SEMANTICS_INTERPRETER_ADDRESS_H_
 
 #include <cstdint>
-#include <iostream>
 #include <string>
 #include <vector>
 
+#include "common/ostream.h"
 #include "executable_semantics/interpreter/field_path.h"
 
 namespace Carbon {
@@ -38,9 +38,8 @@ class Address {
   // Currently, that representation consists of an integer index identifying
   // the whole memory allocation, and an optional FieldPath specifying a
   // particular field within that allocation.
-  friend auto operator<<(std::ostream& out, const Address& a) -> std::ostream& {
-    out << "Address(" << a.index << ")" << a.field_path;
-    return out;
+  void Print(llvm::raw_ostream& out) const {
+    out << "Address(" << index << ")" << field_path;
   }
 
   // If *this represents the address of an object with a field named

+ 4 - 5
executable_semantics/interpreter/field_path.h

@@ -5,10 +5,11 @@
 #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_FIELD_PATH_H_
 #define EXECUTABLE_SEMANTICS_INTERPRETER_FIELD_PATH_H_
 
-#include <ostream>
 #include <string>
 #include <vector>
 
+#include "common/ostream.h"
+
 namespace Carbon {
 
 // Given some initial Value, a FieldPath identifies a sub-Value within it,
@@ -43,12 +44,10 @@ class FieldPath {
     components.push_back(std::move(name));
   }
 
-  friend auto operator<<(std::ostream& out, const FieldPath& path)
-      -> std::ostream& {
-    for (const std::string& component : path.components) {
+  void Print(llvm::raw_ostream& out) const {
+    for (const std::string& component : components) {
       out << "." << component;
     }
-    return out;
   }
 
  private:

+ 3 - 4
executable_semantics/interpreter/frame.cpp

@@ -10,10 +10,9 @@
 
 namespace Carbon {
 
-void PrintFrame(Frame* frame, std::ostream& out) {
-  out << frame->name;
-  out << "{";
-  Action::PrintList(frame->todo, out);
+void Frame::Print(llvm::raw_ostream& out) const {
+  out << name << "{";
+  Action::PrintList(todo, out);
   out << "}";
 }
 

+ 3 - 2
executable_semantics/interpreter/frame.h

@@ -8,6 +8,7 @@
 #include <list>
 #include <string>
 
+#include "common/ostream.h"
 #include "executable_semantics/interpreter/action.h"
 #include "executable_semantics/interpreter/address.h"
 #include "executable_semantics/interpreter/dictionary.h"
@@ -45,9 +46,9 @@ struct Frame {
 
   Frame(std::string n, Stack<Scope*> s, Stack<Action*> c)
       : name(std::move(std::move(n))), scopes(s), todo(c), continuation() {}
-};
 
-void PrintFrame(Frame* frame, std::ostream& out);
+  void Print(llvm::raw_ostream& out) const;
+};
 
 }  // namespace Carbon
 

+ 7 - 9
executable_semantics/interpreter/heap.cpp

@@ -23,7 +23,7 @@ auto Heap::Read(const Address& a, int line_num) -> const Value* {
   return values_[a.index]->GetField(a.field_path, line_num);
 }
 
-auto Heap::Write(const Address& a, const Value* v, int line_num) -> void {
+void Heap::Write(const Address& a, const Value* v, int line_num) {
   CHECK(v != nullptr);
   this->CheckAlive(a, line_num);
   values_[a.index] = values_[a.index]->SetField(a.field_path, v, line_num);
@@ -31,9 +31,8 @@ auto Heap::Write(const Address& a, const Value* v, int line_num) -> void {
 
 void Heap::CheckAlive(const Address& address, int line_num) {
   if (!alive_[address.index]) {
-    std::cerr << line_num << ": undefined behavior: access to dead value ";
-    PrintValue(values_[address.index], std::cerr);
-    std::cerr << std::endl;
+    llvm::errs() << line_num << ": undefined behavior: access to dead value "
+                 << *values_[address.index] << "\n";
     exit(-1);
   }
 }
@@ -43,24 +42,23 @@ void Heap::Deallocate(const Address& address) {
   if (alive_[address.index]) {
     alive_[address.index] = false;
   } else {
-    std::cerr << "runtime error, deallocating an already dead value"
-              << std::endl;
+    llvm::errs() << "runtime error, deallocating an already dead value\n";
     exit(-1);
   }
 }
 
-void Heap::PrintHeap(std::ostream& out) {
+void Heap::Print(llvm::raw_ostream& out) const {
   for (size_t i = 0; i < values_.size(); ++i) {
     PrintAddress(Address(i), out);
     out << ", ";
   }
 }
 
-auto Heap::PrintAddress(const Address& a, std::ostream& out) -> void {
+void Heap::PrintAddress(const Address& a, llvm::raw_ostream& out) const {
   if (!alive_[a.index]) {
     out << "!!";
   }
-  PrintValue(values_[a.index], out);
+  out << *values_[a.index];
 }
 
 }  // namespace Carbon

+ 5 - 5
executable_semantics/interpreter/heap.h

@@ -5,9 +5,9 @@
 #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_MEMORY_H_
 #define EXECUTABLE_SEMANTICS_INTERPRETER_MEMORY_H_
 
-#include <ostream>
 #include <vector>
 
+#include "common/ostream.h"
 #include "executable_semantics/interpreter/address.h"
 #include "executable_semantics/interpreter/value.h"
 
@@ -28,19 +28,19 @@ class Heap {
 
   // Writes the given value at the address in the heap after
   // checking that the address is alive.
-  auto Write(const Address& a, const Value* v, int line_num) -> void;
+  void Write(const Address& a, const Value* v, int line_num);
 
   // Put the given value on the heap and mark it as alive.
   auto AllocateValue(const Value* v) -> Address;
 
   // Marks the object at this address, and all of its sub-objects, as dead.
-  auto Deallocate(const Address& address) -> void;
+  void Deallocate(const Address& address);
 
   // Print the value at the given address to the stream `out`.
-  auto PrintAddress(const Address& a, std::ostream& out) -> void;
+  void PrintAddress(const Address& a, llvm::raw_ostream& out) const;
 
   // Print all the values on the heap to the stream `out`.
-  auto PrintHeap(std::ostream& out) -> void;
+  void Print(llvm::raw_ostream& out) const;
 
  private:
   // Signal an error if the address is no longer alive.

+ 62 - 81
executable_semantics/interpreter/interpreter.cpp

@@ -4,7 +4,6 @@
 
 #include "executable_semantics/interpreter/interpreter.h"
 
-#include <iostream>
 #include <iterator>
 #include <list>
 #include <map>
@@ -26,12 +25,12 @@ State* state = nullptr;
 
 auto PatternMatch(const Value* pat, const Value* val, Env,
                   std::list<std::string>*, int) -> std::optional<Env>;
-auto Step() -> void;
+void Step();
 //
 // Auxiliary Functions
 //
 
-void PrintEnv(Env values, std::ostream& out) {
+void PrintEnv(Env values, llvm::raw_ostream& out) {
   for (const auto& [name, address] : values) {
     out << name << ": ";
     state->heap.PrintAddress(address, out);
@@ -43,9 +42,9 @@ void PrintEnv(Env values, std::ostream& out) {
 // State Operations
 //
 
-void PrintStack(Stack<Frame*> ls, std::ostream& out) {
+void PrintStack(Stack<Frame*> ls, llvm::raw_ostream& out) {
   if (!ls.IsEmpty()) {
-    PrintFrame(ls.Pop(), out);
+    out << *ls.Pop();
     if (!ls.IsEmpty()) {
       out << " :: ";
       PrintStack(ls, out);
@@ -58,17 +57,15 @@ auto CurrentEnv(State* state) -> Env {
   return frame->scopes.Top()->values;
 }
 
-void PrintState(std::ostream& out) {
-  out << "{" << std::endl;
-  out << "stack: ";
+void PrintState(llvm::raw_ostream& out) {
+  out << "{\nstack: ";
   PrintStack(state->stack, out);
-  out << std::endl << "heap: ";
-  state->heap.PrintHeap(out);
+  out << "\nheap: " << state->heap;
   if (!state->stack.IsEmpty() && !state->stack.Top()->scopes.IsEmpty()) {
-    out << std::endl << "values: ";
+    out << "\nvalues: ";
     PrintEnv(CurrentEnv(state), out);
   }
-  out << std::endl << "}" << std::endl;
+  out << "\n}\n";
 }
 
 auto EvalPrim(Operator op, const std::vector<const Value*>& args, int line_num)
@@ -98,7 +95,7 @@ auto EvalPrim(Operator op, const std::vector<const Value*>& args, int line_num)
     case Operator::Ptr:
       return Value::MakePointerType(args[0]);
     case Operator::Deref:
-      std::cerr << line_num << ": dereference not implemented yet\n";
+      llvm::errs() << line_num << ": dereference not implemented yet\n";
       exit(-1);
   }
 }
@@ -184,8 +181,8 @@ void CallFunction(int line_num, std::vector<const Value*> operas,
           PatternMatch(operas[0]->GetFunctionValue().param, operas[1], globals,
                        &params, line_num);
       if (!matches) {
-        std::cerr << "internal error in call_function, pattern match failed"
-                  << std::endl;
+        llvm::errs()
+            << "internal error in call_function, pattern match failed\n";
         exit(-1);
       }
       // Create the new frame and push it on the stack
@@ -213,9 +210,8 @@ void CallFunction(int line_num, std::vector<const Value*> operas,
       break;
     }
     default:
-      std::cerr << line_num << ": in call, expected a function, not ";
-      PrintValue(operas[0], std::cerr);
-      std::cerr << std::endl;
+      llvm::errs() << line_num << ": in call, expected a function, not "
+                   << *operas[0] << "\n";
       exit(-1);
   }
 }
@@ -224,7 +220,7 @@ void DeallocateScope(int line_num, Scope* scope) {
   for (const auto& l : scope->locals) {
     std::optional<Address> a = scope->values.Get(l);
     if (!a) {
-      std::cerr << "internal error in DeallocateScope" << std::endl;
+      llvm::errs() << "internal error in DeallocateScope\n";
       exit(-1);
     }
     state->heap.Deallocate(*a);
@@ -275,8 +271,8 @@ auto PatternMatch(const Value* p, const Value* v, Env values,
         case ValKind::TupleValue: {
           if (p->GetTupleValue().elements.size() !=
               v->GetTupleValue().elements.size()) {
-            std::cerr << "runtime error: arity mismatch in tuple pattern match"
-                      << std::endl;
+            llvm::errs()
+                << "runtime error: arity mismatch in tuple pattern match\n";
             exit(-1);
           }
           for (const TupleElement& pattern_element :
@@ -284,10 +280,8 @@ auto PatternMatch(const Value* p, const Value* v, Env values,
             const Value* value_field =
                 v->GetTupleValue().FindField(pattern_element.name);
             if (value_field == nullptr) {
-              std::cerr << "runtime error: field " << pattern_element.name
-                        << "not in ";
-              PrintValue(v, std::cerr);
-              std::cerr << std::endl;
+              llvm::errs() << "runtime error: field " << pattern_element.name
+                           << "not in " << *v << "\n";
               exit(-1);
             }
             std::optional<Env> matches = PatternMatch(
@@ -300,10 +294,9 @@ auto PatternMatch(const Value* p, const Value* v, Env values,
           return values;
         }
         default:
-          std::cerr
-              << "internal error, expected a tuple value in pattern, not ";
-          PrintValue(v, std::cerr);
-          std::cerr << std::endl;
+          llvm::errs()
+              << "internal error, expected a tuple value in pattern, not " << *v
+              << "\n";
           exit(-1);
       }
     case ValKind::AlternativeValue:
@@ -324,11 +317,10 @@ auto PatternMatch(const Value* p, const Value* v, Env values,
           return *matches;
         }
         default:
-          std::cerr
+          llvm::errs()
               << "internal error, expected a choice alternative in pattern, "
-                 "not ";
-          PrintValue(v, std::cerr);
-          std::cerr << std::endl;
+                 "not "
+              << *v << "\n";
           exit(-1);
       }
     case ValKind::FunctionType:
@@ -367,8 +359,8 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
         case ValKind::TupleValue: {
           if (pat->GetTupleValue().elements.size() !=
               val->GetTupleValue().elements.size()) {
-            std::cerr << "runtime error: arity mismatch in tuple pattern match"
-                      << std::endl;
+            llvm::errs()
+                << "runtime error: arity mismatch in tuple pattern match\n";
             exit(-1);
           }
           for (const TupleElement& pattern_element :
@@ -376,10 +368,8 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
             const Value* value_field =
                 val->GetTupleValue().FindField(pattern_element.name);
             if (value_field == nullptr) {
-              std::cerr << "runtime error: field " << pattern_element.name
-                        << "not in ";
-              PrintValue(val, std::cerr);
-              std::cerr << std::endl;
+              llvm::errs() << "runtime error: field " << pattern_element.name
+                           << "not in " << *val << "\n";
               exit(-1);
             }
             PatternAssignment(pattern_element.value, value_field, line_num);
@@ -387,11 +377,10 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
           break;
         }
         default:
-          std::cerr
+          llvm::errs()
               << "internal error, expected a tuple value on right-hand-side, "
-                 "not ";
-          PrintValue(val, std::cerr);
-          std::cerr << std::endl;
+                 "not "
+              << *val << "\n";
           exit(-1);
       }
       break;
@@ -403,7 +392,7 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
                   val->GetAlternativeValue().choice_name ||
               pat->GetAlternativeValue().alt_name !=
                   val->GetAlternativeValue().alt_name) {
-            std::cerr << "internal error in pattern assignment" << std::endl;
+            llvm::errs() << "internal error in pattern assignment\n";
             exit(-1);
           }
           PatternAssignment(pat->GetAlternativeValue().argument,
@@ -411,18 +400,17 @@ void PatternAssignment(const Value* pat, const Value* val, int line_num) {
           break;
         }
         default:
-          std::cerr
+          llvm::errs()
               << "internal error, expected an alternative in left-hand-side, "
-                 "not ";
-          PrintValue(val, std::cerr);
-          std::cerr << std::endl;
+                 "not "
+              << *val << "\n";
           exit(-1);
       }
       break;
     }
     default:
       if (!ValueEqual(pat, val, line_num)) {
-        std::cerr << "internal error in pattern assignment" << std::endl;
+        llvm::errs() << "internal error in pattern assignment\n";
         exit(-1);
       }
   }
@@ -435,9 +423,7 @@ void StepLvalue() {
   Action* act = frame->todo.Top();
   const Expression* exp = act->GetLValAction().exp;
   if (tracing_output) {
-    std::cout << "--- step lvalue ";
-    PrintExp(exp);
-    std::cout << " --->" << std::endl;
+    llvm::outs() << "--- step lvalue " << *exp << " --->\n";
   }
   switch (exp->tag()) {
     case ExpressionKind::IdentifierExpression: {
@@ -446,8 +432,8 @@ void StepLvalue() {
       std::optional<Address> pointer =
           CurrentEnv(state).Get(exp->GetIdentifierExpression().name);
       if (!pointer) {
-        std::cerr << exp->line_num << ": could not find `"
-                  << exp->GetIdentifierExpression().name << "`" << std::endl;
+        llvm::errs() << exp->line_num << ": could not find `"
+                     << exp->GetIdentifierExpression().name << "`\n";
         exit(-1);
       }
       const Value* v = Value::MakePointerValue(*pointer);
@@ -528,9 +514,7 @@ void StepLvalue() {
     case ExpressionKind::AutoTypeLiteral:
     case ExpressionKind::ContinuationTypeLiteral:
     case ExpressionKind::BindingExpression: {
-      std::cerr << "Can't treat expression as lvalue: ";
-      PrintExp(exp);
-      std::cerr << std::endl;
+      llvm::errs() << "Can't treat expression as lvalue: " << *exp << "\n";
       exit(-1);
     }
   }
@@ -543,9 +527,7 @@ void StepExp() {
   Action* act = frame->todo.Top();
   const Expression* exp = act->GetExpressionAction().exp;
   if (tracing_output) {
-    std::cout << "--- step exp ";
-    PrintExp(exp);
-    std::cout << " --->" << std::endl;
+    llvm::outs() << "--- step exp " << *exp << " --->\n";
   }
   switch (exp->tag()) {
     case ExpressionKind::BindingExpression: {
@@ -581,9 +563,8 @@ void StepExp() {
             std::string f = std::to_string(act->results[1]->GetIntValue());
             const Value* field = tuple->GetTupleValue().FindField(f);
             if (field == nullptr) {
-              std::cerr << "runtime error, field " << f << " not in ";
-              PrintValue(tuple, std::cerr);
-              std::cerr << std::endl;
+              llvm::errs() << "runtime error, field " << f << " not in "
+                           << *tuple << "\n";
               exit(-1);
             }
             frame->todo.Pop(1);
@@ -591,10 +572,10 @@ void StepExp() {
             break;
           }
           default:
-            std::cerr
+            llvm::errs()
                 << "runtime type error, expected a tuple in field access, "
-                   "not ";
-            PrintValue(tuple, std::cerr);
+                   "not "
+                << *tuple << "\n";
             exit(-1);
         }
       }
@@ -649,8 +630,8 @@ void StepExp() {
       std::optional<Address> pointer =
           CurrentEnv(state).Get(exp->GetIdentifierExpression().name);
       if (!pointer) {
-        std::cerr << exp->line_num << ": could not find `"
-                  << exp->GetIdentifierExpression().name << "`" << std::endl;
+        llvm::errs() << exp->line_num << ": could not find `"
+                     << exp->GetIdentifierExpression().name << "`\n";
         exit(-1);
       }
       const Value* pointee = state->heap.Read(*pointer, exp->line_num);
@@ -710,7 +691,7 @@ void StepExp() {
         frame->todo.Pop(1);
         CallFunction(exp->line_num, act->results, state);
       } else {
-        std::cerr << "internal error in handle_value with Call" << std::endl;
+        llvm::errs() << "internal error in handle_value with Call\n";
         exit(-1);
       }
       break;
@@ -809,9 +790,9 @@ void StepStmt() {
   const Statement* stmt = act->GetStatementAction().stmt;
   CHECK(stmt != nullptr) << "null statement!";
   if (tracing_output) {
-    std::cout << "--- step stmt ";
-    PrintStatement(stmt, 1);
-    std::cout << " --->" << std::endl;
+    llvm::outs() << "--- step stmt ";
+    stmt->PrintDepth(1, llvm::outs());
+    llvm::outs() << " --->\n";
   }
   switch (stmt->tag()) {
     case StatementKind::Match:
@@ -960,9 +941,9 @@ void StepStmt() {
             PatternMatch(p, v, frame->scopes.Top()->values,
                          &frame->scopes.Top()->locals, stmt->line_num);
         if (!matches) {
-          std::cerr << stmt->line_num
-                    << ": internal error in variable definition, match failed"
-                    << std::endl;
+          llvm::errs()
+              << stmt->line_num
+              << ": internal error in variable definition, match failed\n";
           exit(-1);
         }
         frame->scopes.Top()->values = *matches;
@@ -1114,8 +1095,8 @@ void StepStmt() {
 void Step() {
   Frame* frame = state->stack.Top();
   if (frame->todo.IsEmpty()) {
-    std::cerr << "runtime error: fell off end of function " << frame->name
-              << " without `return`" << std::endl;
+    llvm::errs() << "runtime error: fell off end of function " << frame->name
+                 << " without `return`\n";
     exit(-1);
   }
 
@@ -1143,7 +1124,7 @@ void Step() {
 auto InterpProgram(std::list<Declaration>* fs) -> int {
   state = new State();  // Runtime state.
   if (tracing_output) {
-    std::cout << "********** initializing globals **********" << std::endl;
+    llvm::outs() << "********** initializing globals **********\n";
   }
   InitGlobals(fs);
 
@@ -1156,8 +1137,8 @@ auto InterpProgram(std::list<Declaration>* fs) -> int {
   state->stack = Stack(frame);
 
   if (tracing_output) {
-    std::cout << "********** calling main function **********" << std::endl;
-    PrintState(std::cout);
+    llvm::outs() << "********** calling main function **********\n";
+    PrintState(llvm::outs());
   }
 
   while (state->stack.CountExceeds(1) ||
@@ -1165,7 +1146,7 @@ auto InterpProgram(std::list<Declaration>* fs) -> int {
          state->stack.Top()->todo.Top()->tag() != ActionKind::ValAction) {
     Step();
     if (tracing_output) {
-      PrintState(std::cout);
+      PrintState(llvm::outs());
     }
   }
   const Value* v = state->stack.Top()->todo.Top()->GetValAction().val;

+ 2 - 1
executable_semantics/interpreter/interpreter.h

@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/declaration.h"
 #include "executable_semantics/interpreter/frame.h"
 #include "executable_semantics/interpreter/heap.h"
@@ -27,7 +28,7 @@ struct State {
 extern State* state;
 
 void InitEnv(const Declaration& d, Env* env);
-void PrintStack(Stack<Frame*> ls, std::ostream& out);
+void PrintStack(Stack<Frame*> ls, llvm::raw_ostream& out);
 void PrintEnv(Env values);
 
 /***** Interpreters *****/

+ 57 - 86
executable_semantics/interpreter/typecheck.cpp

@@ -5,7 +5,6 @@
 #include "executable_semantics/interpreter/typecheck.h"
 
 #include <algorithm>
-#include <iostream>
 #include <iterator>
 #include <map>
 #include <set>
@@ -20,12 +19,9 @@ namespace Carbon {
 void ExpectType(int line_num, const std::string& context, const Value* expected,
                 const Value* actual) {
   if (!TypeEqual(expected, actual)) {
-    std::cerr << line_num << ": type error in " << context << std::endl;
-    std::cerr << "expected: ";
-    PrintValue(expected, std::cerr);
-    std::cerr << std::endl << "actual: ";
-    PrintValue(actual, std::cerr);
-    std::cerr << std::endl;
+    llvm::errs() << line_num << ": type error in " << context << "\n"
+                 << "expected: " << *expected << "\n"
+                 << "actual: " << *actual << "\n";
     exit(-1);
   }
 }
@@ -33,25 +29,13 @@ void ExpectType(int line_num, const std::string& context, const Value* expected,
 void ExpectPointerType(int line_num, const std::string& context,
                        const Value* actual) {
   if (actual->tag() != ValKind::PointerType) {
-    std::cerr << line_num << ": type error in " << context << std::endl;
-    std::cerr << "expected a pointer type\n";
-    std::cerr << "actual: ";
-    PrintValue(actual, std::cerr);
-    std::cerr << std::endl;
+    llvm::errs() << line_num << ": type error in " << context << "\n"
+                 << "expected a pointer type\n"
+                 << "actual: " << *actual << "\n";
     exit(-1);
   }
 }
 
-void PrintErrorString(const std::string& s) { std::cerr << s; }
-
-void PrintTypeEnv(TypeEnv types, std::ostream& out) {
-  for (const auto& [name, value] : types) {
-    out << name << ": ";
-    PrintValue(value, out);
-    out << ", ";
-  }
-}
-
 // Reify type to type expression.
 auto ReifyType(const Value* t, int line_num) -> const Expression* {
   switch (t->tag()) {
@@ -83,9 +67,7 @@ auto ReifyType(const Value* t, int line_num) -> const Expression* {
       return Expression::MakePrimitiveOperatorExpression(
           0, Operator::Ptr, {ReifyType(t->GetPointerType().type, line_num)});
     default:
-      std::cerr << line_num << ": expected a type, not ";
-      PrintValue(t, std::cerr);
-      std::cerr << std::endl;
+      llvm::errs() << line_num << ": expected a type, not " << *t << "\n";
       exit(-1);
   }
 }
@@ -113,39 +95,37 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
   if (tracing_output) {
     switch (context) {
       case TCContext::ValueContext:
-        std::cout << "checking expression ";
+        llvm::outs() << "checking expression ";
         break;
       case TCContext::PatternContext:
-        std::cout << "checking pattern, ";
+        llvm::outs() << "checking pattern, ";
         if (expected) {
-          std::cout << "expecting ";
-          PrintValue(expected, std::cerr);
+          llvm::outs() << "expecting " << *expected;
         }
-        std::cout << ", ";
+        llvm::outs() << ", ";
         break;
       case TCContext::TypeContext:
-        std::cout << "checking type ";
+        llvm::outs() << "checking type ";
         break;
     }
-    PrintExp(e);
-    std::cout << std::endl;
+    llvm::outs() << *e << "\n";
   }
   switch (e->tag()) {
     case ExpressionKind::BindingExpression: {
       if (context != TCContext::PatternContext) {
-        std::cerr
+        llvm::errs()
             << e->line_num
             << ": compilation error, pattern variables are only allowed in "
                "pattern context"
-            << std::endl;
+            << "\n";
         exit(-1);
       }
       auto t = InterpExp(values, e->GetBindingExpression().type);
       if (t->tag() == ValKind::AutoType) {
         if (expected == nullptr) {
-          std::cerr << e->line_num
-                    << ": compilation error, auto not allowed here"
-                    << std::endl;
+          llvm::errs() << e->line_num
+                       << ": compilation error, auto not allowed here"
+                       << "\n";
           exit(-1);
         } else {
           t = expected;
@@ -172,10 +152,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
           std::string f = std::to_string(i);
           const Value* field_t = t->GetTupleValue().FindField(f);
           if (field_t == nullptr) {
-            std::cerr << e->line_num << ": compilation error, field " << f
-                      << " is not in the tuple ";
-            PrintValue(t, std::cerr);
-            std::cerr << std::endl;
+            llvm::errs() << e->line_num << ": compilation error, field " << f
+                         << " is not in the tuple " << *t << "\n";
             exit(-1);
           }
           auto new_e = Expression::MakeIndexExpression(
@@ -183,8 +161,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
           return TCResult(new_e, field_t, res.types);
         }
         default:
-          std::cerr << e->line_num << ": compilation error, expected a tuple"
-                    << std::endl;
+          llvm::errs() << e->line_num
+                       << ": compilation error, expected a tuple\n";
           exit(-1);
       }
     }
@@ -193,15 +171,14 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
       std::vector<TupleElement> arg_types;
       auto new_types = types;
       if (expected && expected->tag() != ValKind::TupleValue) {
-        std::cerr << e->line_num << ": compilation error, didn't expect a tuple"
-                  << std::endl;
+        llvm::errs() << e->line_num
+                     << ": compilation error, didn't expect a tuple\n";
         exit(-1);
       }
       if (expected && e->GetTupleLiteral().fields.size() !=
                           expected->GetTupleValue().elements.size()) {
-        std::cerr << e->line_num
-                  << ": compilation error, tuples of different length"
-                  << std::endl;
+        llvm::errs() << e->line_num
+                     << ": compilation error, tuples of different length\n";
         exit(-1);
       }
       int i = 0;
@@ -210,11 +187,11 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
         const Value* arg_expected = nullptr;
         if (expected && expected->tag() == ValKind::TupleValue) {
           if (expected->GetTupleValue().elements[i].name != arg->name) {
-            std::cerr << e->line_num
-                      << ": compilation error, field names do not match, "
-                      << "expected "
-                      << expected->GetTupleValue().elements[i].name
-                      << " but got " << arg->name << std::endl;
+            llvm::errs()
+                << e->line_num
+                << ": compilation error, field names do not match, expected "
+                << expected->GetTupleValue().elements[i].name << " but got "
+                << arg->name << "\n";
             exit(-1);
           }
           arg_expected = expected->GetTupleValue().elements[i].value;
@@ -251,10 +228,10 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
               return TCResult(new_e, method.second, res.types);
             }
           }
-          std::cerr << e->line_num << ": compilation error, struct "
-                    << t->GetStructType().name
-                    << " does not have a field named "
-                    << e->GetFieldAccessExpression().field << std::endl;
+          llvm::errs() << e->line_num << ": compilation error, struct "
+                       << t->GetStructType().name
+                       << " does not have a field named "
+                       << e->GetFieldAccessExpression().field << "\n";
           exit(-1);
         case ValKind::TupleValue:
           for (const TupleElement& field : t->GetTupleValue().elements) {
@@ -264,10 +241,10 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
               return TCResult(new_e, field.value, res.types);
             }
           }
-          std::cerr << e->line_num << ": compilation error, struct "
-                    << t->GetStructType().name
-                    << " does not have a field named "
-                    << e->GetFieldAccessExpression().field << std::endl;
+          llvm::errs() << e->line_num << ": compilation error, struct "
+                       << t->GetStructType().name
+                       << " does not have a field named "
+                       << e->GetFieldAccessExpression().field << "\n";
           exit(-1);
         case ValKind::ChoiceType:
           for (auto vt = t->GetChoiceType().alternatives.begin();
@@ -279,18 +256,17 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
               return TCResult(new_e, fun_ty, res.types);
             }
           }
-          std::cerr << e->line_num << ": compilation error, struct "
-                    << t->GetStructType().name
-                    << " does not have a field named "
-                    << e->GetFieldAccessExpression().field << std::endl;
+          llvm::errs() << e->line_num << ": compilation error, struct "
+                       << t->GetStructType().name
+                       << " does not have a field named "
+                       << e->GetFieldAccessExpression().field << "\n";
           exit(-1);
 
         default:
-          std::cerr << e->line_num
-                    << ": compilation error in field access, expected a struct"
-                    << std::endl;
-          PrintExp(e);
-          std::cerr << std::endl;
+          llvm::errs()
+              << e->line_num
+              << ": compilation error in field access, expected a struct\n"
+              << *e << "\n";
           exit(-1);
       }
     }
@@ -300,8 +276,8 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
       if (type) {
         return TCResult(e, *type, types);
       } else {
-        std::cerr << e->line_num << ": could not find `"
-                  << e->GetIdentifierExpression().name << "`" << std::endl;
+        llvm::errs() << e->line_num << ": could not find `"
+                     << e->GetIdentifierExpression().name << "`\n";
         exit(-1);
       }
     }
@@ -382,11 +358,9 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
           return TCResult(new_e, fun_t->GetFunctionType().ret, arg_res.types);
         }
         default: {
-          std::cerr << e->line_num
-                    << ": compilation error in call, expected a function"
-                    << std::endl;
-          PrintExp(e);
-          std::cerr << std::endl;
+          llvm::errs() << e->line_num
+                       << ": compilation error in call, expected a function\n"
+                       << *e << "\n";
           exit(-1);
         }
       }
@@ -584,9 +558,8 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num)
       return Statement::MakeReturn(line_num,
                                    Expression::MakeTupleLiteral(line_num, {}));
     } else {
-      std::cerr
-          << "control-flow reaches end of non-void function without a return"
-          << std::endl;
+      llvm::errs()
+          << "control-flow reaches end of non-void function without a return\n";
       exit(-1);
     }
   }
@@ -641,11 +614,10 @@ auto CheckOrEnsureReturn(const Statement* stmt, bool void_return, int line_num)
             Statement::MakeReturn(stmt->line_num, Expression::MakeTupleLiteral(
                                                       stmt->line_num, {})));
       } else {
-        std::cerr
+        llvm::errs()
             << stmt->line_num
             << ": control-flow reaches end of non-void function without a "
-               "return"
-            << std::endl;
+               "return\n";
         exit(-1);
       }
   }
@@ -812,8 +784,7 @@ auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext {
   }
 
   if (found_main == false) {
-    std::cerr << "error, program must contain a function named `main`"
-              << std::endl;
+    llvm::errs() << "error, program must contain a function named `main`\n";
     exit(-1);
   }
   return tops;

+ 1 - 4
executable_semantics/interpreter/typecheck.h

@@ -7,6 +7,7 @@
 
 #include <set>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/expression.h"
 #include "executable_semantics/ast/statement.h"
 #include "executable_semantics/interpreter/dictionary.h"
@@ -16,8 +17,6 @@ namespace Carbon {
 
 using TypeEnv = Dictionary<std::string, const Value*>;
 
-void PrintTypeEnv(TypeEnv types);
-
 enum class TCContext { ValueContext, PatternContext, TypeContext };
 
 struct TCResult {
@@ -49,8 +48,6 @@ auto MakeTypeChecked(const Declaration& decl, const TypeEnv& types,
                      const Env& values) -> Declaration;
 auto TopLevel(std::list<Declaration>* fs) -> TypeCheckContext;
 
-void PrintErrorString(const std::string& s);
-
 }  // namespace Carbon
 
 #endif  // EXECUTABLE_SEMANTICS_INTERPRETER_TYPECHECK_H_

+ 33 - 53
executable_semantics/interpreter/value.cpp

@@ -5,7 +5,6 @@
 #include "executable_semantics/interpreter/value.h"
 
 #include <algorithm>
-#include <iostream>
 
 #include "common/check.h"
 
@@ -252,9 +251,8 @@ auto GetMember(const Value* v, const std::string& f, int line_num)
       const Value* field =
           v->GetStructValue().inits->GetTupleValue().FindField(f);
       if (field == nullptr) {
-        std::cerr << "runtime error, member " << f << " not in ";
-        PrintValue(v, std::cerr);
-        std::cerr << std::endl;
+        llvm::errs() << "runtime error, member " << f << " not in " << *v
+                     << "\n";
         exit(-1);
       }
       return field;
@@ -262,26 +260,20 @@ auto GetMember(const Value* v, const std::string& f, int line_num)
     case ValKind::TupleValue: {
       const Value* field = v->GetTupleValue().FindField(f);
       if (field == nullptr) {
-        std::cerr << "field " << f << " not in ";
-        PrintValue(v, std::cerr);
-        std::cerr << std::endl;
+        llvm::errs() << "field " << f << " not in " << *v << "\n";
         exit(-1);
       }
       return field;
     }
     case ValKind::ChoiceType: {
       if (FindInVarValues(f, v->GetChoiceType().alternatives) == nullptr) {
-        std::cerr << "alternative " << f << " not in ";
-        PrintValue(v, std::cerr);
-        std::cerr << std::endl;
+        llvm::errs() << "alternative " << f << " not in " << *v << "\n";
         exit(-1);
       }
       return Value::MakeAlternativeConstructorValue(f, v->GetChoiceType().name);
     }
     default:
-      std::cerr << "field access not allowed for value ";
-      PrintValue(v, std::cerr);
-      std::cerr << std::endl;
+      llvm::errs() << "field access not allowed for value " << *v << "\n";
       exit(-1);
   }
 }
@@ -318,9 +310,7 @@ auto SetFieldImpl(const Value* value,
                                return element.name == *path_begin;
                              });
       if (it == elements.end()) {
-        std::cerr << "field " << *path_begin << " not in ";
-        PrintValue(value, std::cerr);
-        std::cerr << std::endl;
+        llvm::errs() << "field " << *path_begin << " not in " << *value << "\n";
         exit(-1);
       }
       it->value = SetFieldImpl(it->value, path_begin + 1, path_end, field_value,
@@ -328,9 +318,7 @@ auto SetFieldImpl(const Value* value,
       return Value::MakeTupleValue(elements);
     }
     default:
-      std::cerr << "field access not allowed for value ";
-      PrintValue(value, std::cerr);
-      std::cerr << std::endl;
+      llvm::errs() << "field access not allowed for value " << *value << "\n";
       exit(-1);
   }
 }
@@ -343,63 +331,60 @@ auto Value::SetField(const FieldPath& path, const Value* field_value,
                       field_value, line_num);
 }
 
-auto PrintValue(const Value* val, std::ostream& out) -> void {
-  switch (val->tag()) {
+void Value::Print(llvm::raw_ostream& out) const {
+  switch (tag()) {
     case ValKind::AlternativeConstructorValue: {
-      out << val->GetAlternativeConstructorValue().choice_name << "."
-          << val->GetAlternativeConstructorValue().alt_name;
+      out << GetAlternativeConstructorValue().choice_name << "."
+          << GetAlternativeConstructorValue().alt_name;
       break;
     }
     case ValKind::BindingPlaceholderValue: {
-      const BindingPlaceholderValue& placeholder =
-          val->GetBindingPlaceholderValue();
+      const BindingPlaceholderValue& placeholder = GetBindingPlaceholderValue();
       if (placeholder.name.has_value()) {
         out << *placeholder.name;
       } else {
         out << "_";
       }
-      out << ": ";
-      PrintValue(val->GetBindingPlaceholderValue().type, out);
+      out << ": " << *placeholder.type;
       break;
     }
     case ValKind::AlternativeValue: {
-      out << "alt " << val->GetAlternativeValue().choice_name << "."
-          << val->GetAlternativeValue().alt_name << " ";
-      PrintValue(val->GetAlternativeValue().argument, out);
+      out << "alt " << GetAlternativeValue().choice_name << "."
+          << GetAlternativeValue().alt_name << " "
+          << *GetAlternativeValue().argument;
       break;
     }
     case ValKind::StructValue: {
-      out << val->GetStructValue().type->GetStructType().name;
-      PrintValue(val->GetStructValue().inits, out);
+      out << GetStructValue().type->GetStructType().name
+          << *GetStructValue().inits;
       break;
     }
     case ValKind::TupleValue: {
       out << "(";
       bool add_commas = false;
-      for (const TupleElement& element : val->GetTupleValue().elements) {
+      for (const TupleElement& element : GetTupleValue().elements) {
         if (add_commas) {
           out << ", ";
         } else {
           add_commas = true;
         }
 
-        out << element.name << " = ";
-        PrintValue(element.value, out);
+        out << element.name << " = " << *element.value;
       }
       out << ")";
       break;
     }
     case ValKind::IntValue:
-      out << val->GetIntValue();
+      out << GetIntValue();
       break;
     case ValKind::BoolValue:
-      out << std::boolalpha << val->GetBoolValue();
+      out << (GetBoolValue() ? "true" : "false");
       break;
     case ValKind::FunctionValue:
-      out << "fun<" << val->GetFunctionValue().name << ">";
+      out << "fun<" << GetFunctionValue().name << ">";
       break;
     case ValKind::PointerValue:
-      out << "ptr<" << val->GetPointerValue() << ">";
+      out << "ptr<" << GetPointerValue() << ">";
       break;
     case ValKind::BoolType:
       out << "Bool";
@@ -417,20 +402,17 @@ auto PrintValue(const Value* val, std::ostream& out) -> void {
       out << "Continuation";
       break;
     case ValKind::PointerType:
-      PrintValue(val->GetPointerType().type, out);
-      out << "*";
+      out << *GetPointerType().type << "*";
       break;
     case ValKind::FunctionType:
-      out << "fn ";
-      PrintValue(val->GetFunctionType().param, out);
-      out << " -> ";
-      PrintValue(val->GetFunctionType().ret, out);
+      out << "fn " << *GetFunctionType().param << " -> "
+          << *GetFunctionType().ret;
       break;
     case ValKind::StructType:
-      out << "struct " << val->GetStructType().name;
+      out << "struct " << GetStructType().name;
       break;
     case ValKind::ChoiceType:
-      out << "choice " << val->GetChoiceType().name;
+      out << "choice " << GetChoiceType().name;
       break;
     case ValKind::ContinuationValue:
       out << "continuation";
@@ -538,10 +520,9 @@ auto TypeEqual(const Value* t1, const Value* t2) -> bool {
     case ValKind::TypeType:
       return true;
     default:
-      std::cerr << "TypeEqual used to compare non-type values" << std::endl;
-      PrintValue(t1, std::cerr);
-      std::cerr << std::endl;
-      PrintValue(t2, std::cerr);
+      llvm::errs() << "TypeEqual used to compare non-type values\n"
+                   << *t1 << "\n"
+                   << *t2 << "\n";
       exit(-1);
   }
 }
@@ -603,8 +584,7 @@ auto ValueEqual(const Value* v1, const Value* v2, int line_num) -> bool {
     case ValKind::BindingPlaceholderValue:
     case ValKind::AlternativeConstructorValue:
     case ValKind::ContinuationValue:
-      std::cerr << "ValueEqual does not support this kind of value."
-                << std::endl;
+      llvm::errs() << "ValueEqual does not support this kind of value.\n";
       exit(-1);
   }
 }

+ 3 - 2
executable_semantics/interpreter/value.h

@@ -11,6 +11,7 @@
 #include <variant>
 #include <vector>
 
+#include "common/ostream.h"
 #include "executable_semantics/ast/statement.h"
 #include "executable_semantics/interpreter/address.h"
 #include "executable_semantics/interpreter/field_path.h"
@@ -229,6 +230,8 @@ struct Value {
   auto SetField(const FieldPath& path, const Value* field_value,
                 int line_num) const -> const Value*;
 
+  void Print(llvm::raw_ostream& out) const;
+
  private:
   std::variant<IntValue, FunctionValue, PointerValue, BoolValue, StructValue,
                AlternativeValue, TupleValue, IntType, BoolType, TypeType,
@@ -238,8 +241,6 @@ struct Value {
       value;
 };
 
-void PrintValue(const Value* val, std::ostream& out);
-
 auto CopyVal(const Value* val, int line_num) -> const Value*;
 
 auto TypeEqual(const Value* t1, const Value* t2) -> bool;

+ 4 - 0
executable_semantics/main.cpp

@@ -12,6 +12,10 @@
 #include "llvm/Support/CommandLine.h"
 
 int main(int argc, char* argv[]) {
+  // Printing to stderr should flush stdout. This is most noticeable when stderr
+  // is piped to stdout.
+  llvm::errs().tie(&llvm::outs());
+
   using llvm::cl::desc;
   using llvm::cl::opt;
   opt<bool> trace_option("trace", desc("Enable tracing"));

+ 1 - 0
executable_semantics/syntax/BUILD

@@ -29,6 +29,7 @@ cc_library(
     ],
     deps = [
         ":paren_contents",
+        "//common:ostream",
         "//executable_semantics:tracing_flag",
         "//executable_semantics/ast:declaration",
         "//executable_semantics/ast:expression",

+ 9 - 10
executable_semantics/syntax/syntax_helpers.cpp

@@ -4,8 +4,7 @@
 
 #include "executable_semantics/syntax/syntax_helpers.h"
 
-#include <iostream>
-
+#include "common/ostream.h"
 #include "executable_semantics/interpreter/interpreter.h"
 #include "executable_semantics/interpreter/typecheck.h"
 #include "executable_semantics/tracing_flag.h"
@@ -14,11 +13,11 @@ namespace Carbon {
 
 void ExecProgram(std::list<Declaration>* fs) {
   if (tracing_output) {
-    std::cout << "********** source program **********" << std::endl;
+    llvm::outs() << "********** source program **********\n";
     for (const auto& decl : *fs) {
-      decl.Print();
+      llvm::outs() << decl;
     }
-    std::cout << "********** type checking **********" << std::endl;
+    llvm::outs() << "********** type checking **********\n";
   }
   state = new State();  // Compile-time state.
   TypeCheckContext p = TopLevel(fs);
@@ -29,15 +28,15 @@ void ExecProgram(std::list<Declaration>* fs) {
     new_decls.push_back(MakeTypeChecked(decl, top, ct_top));
   }
   if (tracing_output) {
-    std::cout << std::endl;
-    std::cout << "********** type checking complete **********" << std::endl;
+    llvm::outs() << "\n";
+    llvm::outs() << "********** type checking complete **********\n";
     for (const auto& decl : new_decls) {
-      decl.Print();
+      llvm::outs() << decl;
     }
-    std::cout << "********** starting execution **********" << std::endl;
+    llvm::outs() << "********** starting execution **********\n";
   }
   int result = InterpProgram(&new_decls);
-  std::cout << "result: " << result << std::endl;
+  llvm::outs() << "result: " << result << "\n";
 }
 
 }  // namespace Carbon