diff --git a/common/BUILD b/common/BUILD index dd3c1a4a87c3..0b29a90724df 100644 --- a/common/BUILD +++ b/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", + ], +) diff --git a/common/ostream.h b/common/ostream.h new file mode 100644 index 000000000000..c430fbfbbfd8 --- /dev/null +++ b/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 ::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_ diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD index 5b2b4052cba3..20febeee1632 100644 --- a/executable_semantics/ast/BUILD +++ b/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", + ], ) diff --git a/executable_semantics/ast/declaration.cpp b/executable_semantics/ast/declaration.cpp index 1690f05b77fb..f679f18d8682 100644 --- a/executable_semantics/ast/declaration.cpp +++ b/executable_semantics/ast/declaration.cpp @@ -4,8 +4,6 @@ #include "executable_semantics/ast/declaration.h" -#include - namespace Carbon { auto Declaration::MakeFunctionDeclaration(FunctionDefinition definition) @@ -65,41 +63,36 @@ auto Declaration::GetVariableDeclaration() const -> const VariableDeclaration& { return std::get(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; } } diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h index 3f4b78b398f7..9499f5960403 100644 --- a/executable_semantics/ast/declaration.h +++ b/executable_semantics/ast/declaration.h @@ -8,6 +8,7 @@ #include #include +#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); diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 371c989f32ba..c903c1283f65 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -4,8 +4,6 @@ #include "executable_semantics/ast/expression.h" -#include - 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& fields) { +static void PrintFields(llvm::raw_ostream& out, + const std::vector& 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; } } diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index 9f9b7c543d7d..2d9ece6dc976 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -10,6 +10,8 @@ #include #include +#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_ diff --git a/executable_semantics/ast/function_definition.cpp b/executable_semantics/ast/function_definition.cpp index 4599758bfccb..15eb91dc95db 100644 --- a/executable_semantics/ast/function_definition.cpp +++ b/executable_semantics/ast/function_definition.cpp @@ -4,21 +4,16 @@ #include "executable_semantics/ast/function_definition.h" -#include - 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"; } } diff --git a/executable_semantics/ast/function_definition.h b/executable_semantics/ast/function_definition.h index b2dc5c45514f..1bc833c4f839 100644 --- a/executable_semantics/ast/function_definition.h +++ b/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; diff --git a/executable_semantics/ast/member.cpp b/executable_semantics/ast/member.cpp index a38d67975e5f..4032a0617b50 100644 --- a/executable_semantics/ast/member.cpp +++ b/executable_semantics/ast/member.cpp @@ -4,8 +4,6 @@ #include "executable_semantics/ast/member.h" -#include - namespace Carbon { auto Member::MakeFieldMember(int line_num, std::string name, @@ -20,13 +18,11 @@ auto Member::GetFieldMember() const -> const FieldMember& { return std::get(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; } } diff --git a/executable_semantics/ast/member.h b/executable_semantics/ast/member.h index 82a783b3b8cf..68f7afae88ba 100644 --- a/executable_semantics/ast/member.h +++ b/executable_semantics/ast/member.h @@ -7,6 +7,7 @@ #include +#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); diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp index 79d92af3ad98..066ef2226e5a 100644 --- a/executable_semantics/ast/statement.cpp +++ b/executable_semantics/ast/statement.cpp @@ -4,8 +4,6 @@ #include "executable_semantics/ast/statement.h" -#include - #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 diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index 7409269beb8d..499deb032a3b 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -7,6 +7,7 @@ #include +#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_ diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD index 59014046e2c4..4f4c1a6963b9 100644 --- a/executable_semantics/interpreter/BUILD +++ b/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", ], ) diff --git a/executable_semantics/interpreter/action.cpp b/executable_semantics/interpreter/action.cpp index 1e9105f5436b..cc8fec0c66ef 100644 --- a/executable_semantics/interpreter/action.cpp +++ b/executable_semantics/interpreter/action.cpp @@ -4,7 +4,6 @@ #include "executable_semantics/interpreter/action.h" -#include #include #include #include @@ -57,19 +56,19 @@ auto Action::GetValAction() const -> const ValAction& { return std::get(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 ls, std::ostream& out) { +void Action::PrintList(Stack ls, llvm::raw_ostream& out) { if (!ls.IsEmpty()) { - ls.Pop()->Print(out); + out << *ls.Pop(); if (!ls.IsEmpty()) { out << " :: "; PrintList(ls, out); diff --git a/executable_semantics/interpreter/action.h b/executable_semantics/interpreter/action.h index 6d18d8513a03..73bf3eef33ed 100644 --- a/executable_semantics/interpreter/action.h +++ b/executable_semantics/interpreter/action.h @@ -5,9 +5,9 @@ #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_ #define EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_ -#include #include +#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 ls, std::ostream& out); + static void PrintList(Stack 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); diff --git a/executable_semantics/interpreter/address.h b/executable_semantics/interpreter/address.h index f8b19714928d..705bf793a515 100644 --- a/executable_semantics/interpreter/address.h +++ b/executable_semantics/interpreter/address.h @@ -6,10 +6,10 @@ #define EXECUTABLE_SEMANTICS_INTERPRETER_ADDRESS_H_ #include -#include #include #include +#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 diff --git a/executable_semantics/interpreter/field_path.h b/executable_semantics/interpreter/field_path.h index 926f5eb2df5c..df2064cd584c 100644 --- a/executable_semantics/interpreter/field_path.h +++ b/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 #include #include +#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: diff --git a/executable_semantics/interpreter/frame.cpp b/executable_semantics/interpreter/frame.cpp index 3a9e665e5cf8..ca21ab3e6ed9 100644 --- a/executable_semantics/interpreter/frame.cpp +++ b/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 << "}"; } diff --git a/executable_semantics/interpreter/frame.h b/executable_semantics/interpreter/frame.h index abd132f12669..a3521fe8f7b6 100644 --- a/executable_semantics/interpreter/frame.h +++ b/executable_semantics/interpreter/frame.h @@ -8,6 +8,7 @@ #include #include +#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 s, Stack 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 diff --git a/executable_semantics/interpreter/heap.cpp b/executable_semantics/interpreter/heap.cpp index 95bb6389f340..c8b6305fb538 100644 --- a/executable_semantics/interpreter/heap.cpp +++ b/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 diff --git a/executable_semantics/interpreter/heap.h b/executable_semantics/interpreter/heap.h index a32cddcd4e0f..bb820da477d3 100644 --- a/executable_semantics/interpreter/heap.h +++ b/executable_semantics/interpreter/heap.h @@ -5,9 +5,9 @@ #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_MEMORY_H_ #define EXECUTABLE_SEMANTICS_INTERPRETER_MEMORY_H_ -#include #include +#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. diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 0682459ce38e..ebeca757f2f8 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -4,7 +4,6 @@ #include "executable_semantics/interpreter/interpreter.h" -#include #include #include #include @@ -26,12 +25,12 @@ State* state = nullptr; auto PatternMatch(const Value* pat, const Value* val, Env, std::list*, int) -> std::optional; -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 ls, std::ostream& out) { +void PrintStack(Stack 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& args, int line_num) @@ -98,7 +95,7 @@ auto EvalPrim(Operator op, const std::vector& 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 operas, PatternMatch(operas[0]->GetFunctionValue().param, operas[1], globals, ¶ms, 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 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
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 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
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
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* 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* 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* 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; diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index 047b1b70b108..e4bbc9b9a0cb 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -9,6 +9,7 @@ #include #include +#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 ls, std::ostream& out); +void PrintStack(Stack ls, llvm::raw_ostream& out); void PrintEnv(Env values); /***** Interpreters *****/ diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index f67393b29f5d..68565d29900c 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/executable_semantics/interpreter/typecheck.cpp @@ -5,7 +5,6 @@ #include "executable_semantics/interpreter/typecheck.h" #include -#include #include #include #include @@ -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 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* 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; diff --git a/executable_semantics/interpreter/typecheck.h b/executable_semantics/interpreter/typecheck.h index ab8324f06b13..432089228cb6 100644 --- a/executable_semantics/interpreter/typecheck.h +++ b/executable_semantics/interpreter/typecheck.h @@ -7,6 +7,7 @@ #include +#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; -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* fs) -> TypeCheckContext; -void PrintErrorString(const std::string& s); - } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_INTERPRETER_TYPECHECK_H_ diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 55aef9e65403..6f9491bfc21e 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -5,7 +5,6 @@ #include "executable_semantics/interpreter/value.h" #include -#include #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); } } diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index c1a642484fcc..4417096c4c88 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -11,6 +11,7 @@ #include #include +#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 const Value*; auto TypeEqual(const Value* t1, const Value* t2) -> bool; diff --git a/executable_semantics/main.cpp b/executable_semantics/main.cpp index f456eaab094e..a37186121383 100644 --- a/executable_semantics/main.cpp +++ b/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 trace_option("trace", desc("Enable tracing")); diff --git a/executable_semantics/syntax/BUILD b/executable_semantics/syntax/BUILD index 6a1b35520389..50788bf42472 100644 --- a/executable_semantics/syntax/BUILD +++ b/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", diff --git a/executable_semantics/syntax/syntax_helpers.cpp b/executable_semantics/syntax/syntax_helpers.cpp index 1aad7585868c..db42c37abf2e 100644 --- a/executable_semantics/syntax/syntax_helpers.cpp +++ b/executable_semantics/syntax/syntax_helpers.cpp @@ -4,8 +4,7 @@ #include "executable_semantics/syntax/syntax_helpers.h" -#include - +#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* 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* 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