diff --git a/common/check.h b/common/check.h index be9d4f6e5054..fa21267254d0 100644 --- a/common/check.h +++ b/common/check.h @@ -17,19 +17,24 @@ class ExitingStream { LLVM_ATTRIBUTE_NORETURN ~ExitingStream() { // Finish with a newline. llvm::errs() << "\n"; - exit(-1); + if (treat_as_bug) { + std::abort(); + } else { + std::exit(-1); + } } // Indicates that initial input is in, so this is where a ": " should be added // before user input. - ExitingStream& add_separator() { + ExitingStream& AddSeparator() { separator = true; return *this; } - // Prints a stack traces. - ExitingStream& print_stack() { - llvm::sys::PrintStackTrace(llvm::errs()); + // Indicates that the program is exiting due to a bug in the program, rather + // than, e.g., invalid input. + ExitingStream& TreatAsBug() { + treat_as_bug = true; return *this; } @@ -51,6 +56,9 @@ class ExitingStream { private: // Whether a separator should be printed if << is used again. bool separator = false; + + // Whether the program is exiting due to a bug. + bool treat_as_bug = false; }; // Checks the given condition, and if it's false, prints a stack, streams the @@ -60,16 +68,16 @@ class ExitingStream { // For example: // CHECK(is_valid) << "Data is not valid!"; #define CHECK(condition) \ - (!(condition)) && \ - (Carbon::ExitingStream().print_stack() << "CHECK failure: " #condition) \ - .add_separator() + (!(condition)) && (Carbon::ExitingStream() << "CHECK failure: " #condition) \ + .AddSeparator() \ + .TreatAsBug() // This is similar to CHECK, but is unconditional. Writing FATAL() is clearer // than CHECK(false) because it avoids confusion about control flow. // // For example: // FATAL() << "Unreachable!"; -#define FATAL() Carbon::ExitingStream().print_stack() << "FATAL: " +#define FATAL() Carbon::ExitingStream().TreatAsBug() << "FATAL: " } // namespace Carbon diff --git a/common/check_test.cpp b/common/check_test.cpp index 194e2a93b0b8..b4c9bb8d6ba2 100644 --- a/common/check_test.cpp +++ b/common/check_test.cpp @@ -11,7 +11,7 @@ namespace Carbon { TEST(CheckTest, CheckTrue) { CHECK(true); } TEST(CheckTest, CheckFalse) { - ASSERT_DEATH({ CHECK(false); }, "\nCHECK failure: false\n"); + ASSERT_DEATH({ CHECK(false); }, "CHECK failure: false\n"); } TEST(CheckTest, CheckTrueCallbackNotUsed) { @@ -25,7 +25,7 @@ TEST(CheckTest, CheckTrueCallbackNotUsed) { } TEST(CheckTest, CheckFalseMessage) { - ASSERT_DEATH({ CHECK(false) << "msg"; }, "\nCHECK failure: false: msg\n"); + ASSERT_DEATH({ CHECK(false) << "msg"; }, "CHECK failure: false: msg\n"); } TEST(CheckTest, CheckOutputForms) { @@ -36,13 +36,13 @@ TEST(CheckTest, CheckOutputForms) { } TEST(CheckTest, Fatal) { - ASSERT_DEATH({ FATAL() << "msg"; }, "\nFATAL: msg\n"); + ASSERT_DEATH({ FATAL() << "msg"; }, "FATAL: msg\n"); } auto FatalNoReturnRequired() -> int { FATAL() << "msg"; } TEST(ErrorTest, FatalNoReturnRequired) { - ASSERT_DEATH({ FatalNoReturnRequired(); }, "\nFATAL: msg\n"); + ASSERT_DEATH({ FatalNoReturnRequired(); }, "FATAL: msg\n"); } } // namespace Carbon diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD index 7f15042c46c7..24fadf6f515a 100644 --- a/executable_semantics/interpreter/BUILD +++ b/executable_semantics/interpreter/BUILD @@ -4,18 +4,31 @@ package(default_visibility = ["//executable_semantics:__pkg__"]) +# These currently have to be a single build rule because of a dependency cycle +# in printing. cc_library( - name = "action", - srcs = ["action.cpp"], - hdrs = ["action.h"], + name = "action_frame_and_value", + srcs = [ + "action.cpp", + "frame.cpp", + "value.cpp", + ], + hdrs = [ + "action.h", + "frame.h", + "value.h", + ], deps = [ + ":address", + ":dictionary", + ":field_path", ":stack", - ":value", "//common:ostream", "//executable_semantics/ast:expression", "//executable_semantics/ast:function_definition", "//executable_semantics/ast:statement", "//executable_semantics/common:arena", + "//executable_semantics/common:error", "@llvm-project//llvm:Support", ], ) @@ -56,27 +69,13 @@ cc_library( ], ) -cc_library( - name = "frame", - srcs = ["frame.cpp"], - hdrs = ["frame.h"], - deps = [ - ":action", - ":address", - ":dictionary", - ":stack", - "//common:ostream", - "@llvm-project//llvm:Support", - ], -) - cc_library( name = "heap", srcs = ["heap.cpp"], hdrs = ["heap.h"], deps = [ + ":action_frame_and_value", ":address", - ":value", "//common:ostream", "@llvm-project//llvm:Support", ], @@ -91,11 +90,9 @@ cc_library( "interpreter.h", ], deps = [ - ":action", + ":action_frame_and_value", ":address", - ":frame", ":heap", - ":value", "//common:check", "//common:ostream", "//executable_semantics/ast:declaration", @@ -129,20 +126,3 @@ cc_library( "@llvm-project//llvm:Support", ], ) - -cc_library( - name = "value", - srcs = ["value.cpp"], - hdrs = ["value.h"], - deps = [ - ":address", - ":field_path", - ":stack", - "//common:ostream", - "//executable_semantics/ast:function_definition", - "//executable_semantics/ast:statement", - "//executable_semantics/common:arena", - "//executable_semantics/common:error", - "@llvm-project//llvm:Support", - ], -) diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index a61238460aa0..6e4936fa86f3 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -362,7 +362,8 @@ auto Interpreter::StepLvalue() -> Transition { Ptr act = stack.Top()->todo.Top(); Ptr exp = cast(*act).Exp(); if (tracing_output) { - llvm::outs() << "--- step lvalue " << *exp << " --->\n"; + llvm::outs() << "--- step lvalue " << *exp << " (" << exp->SourceLoc() + << ") --->\n"; } switch (exp->Tag()) { case Expression::Kind::IdentifierExpression: { @@ -449,7 +450,8 @@ auto Interpreter::StepExp() -> Transition { Ptr act = stack.Top()->todo.Top(); Ptr exp = cast(*act).Exp(); if (tracing_output) { - llvm::outs() << "--- step exp " << *exp << " --->\n"; + llvm::outs() << "--- step exp " << *exp << " (" << exp->SourceLoc() + << ") --->\n"; } switch (exp->Tag()) { case Expression::Kind::IndexExpression: { @@ -647,7 +649,8 @@ auto Interpreter::StepPattern() -> Transition { Ptr act = stack.Top()->todo.Top(); Ptr pattern = cast(*act).Pat(); if (tracing_output) { - llvm::outs() << "--- step pattern " << *pattern << " --->\n"; + llvm::outs() << "--- step pattern " << *pattern << " (" + << pattern->SourceLoc() << ") --->\n"; } switch (pattern->Tag()) { case Pattern::Kind::AutoPattern: { @@ -745,7 +748,7 @@ auto Interpreter::StepStmt() -> Transition { if (tracing_output) { llvm::outs() << "--- step stmt "; stmt->PrintDepth(1, llvm::outs()); - llvm::outs() << " --->\n"; + llvm::outs() << " (" << stmt->SourceLoc() << ") --->\n"; } switch (stmt->Tag()) { case Statement::Kind::Match: { diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 452a58427e6f..e5d34b8a5a59 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -9,6 +9,7 @@ #include "common/check.h" #include "executable_semantics/common/arena.h" #include "executable_semantics/common/error.h" +#include "executable_semantics/interpreter/frame.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Casting.h" @@ -232,11 +233,15 @@ void Value::Print(llvm::raw_ostream& out) const { case Value::Kind::VariableType: out << cast(*this).Name(); break; - case Value::Kind::ContinuationValue: - out << "continuation"; - // TODO: Find a way to print useful information about the continuation - // without creating a dependency cycle. + case Value::Kind::ContinuationValue: { + out << "{"; + llvm::ListSeparator sep(" :: "); + for (Ptr frame : cast(*this).Stack()) { + out << sep << *frame; + } + out << "}"; break; + } case Value::Kind::StringType: out << "String"; break;