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.
This commit is contained in:
Jon Meow
2021-07-20 13:16:48 -07:00
committed by GitHub
parent 368fc0063c
commit 8fccecadeb
31 changed files with 391 additions and 458 deletions
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
@@ -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;
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;