diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index e57394165875..5a79ad1dc4aa 100644 --- a/executable_semantics/ast/expression.cpp +++ b/executable_semantics/ast/expression.cpp @@ -17,21 +17,21 @@ namespace Carbon { using llvm::cast; auto ExpressionFromParenContents( - SourceLocation loc, const ParenContents& paren_contents) - -> Ptr { + Ptr arena, SourceLocation loc, + const ParenContents& paren_contents) -> Ptr { std::optional> single_term = paren_contents.SingleTerm(); if (single_term.has_value()) { return *single_term; } else { - return TupleExpressionFromParenContents(loc, paren_contents); + return TupleExpressionFromParenContents(arena, loc, paren_contents); } } auto TupleExpressionFromParenContents( - SourceLocation loc, const ParenContents& paren_contents) - -> Ptr { - return global_arena->New( + Ptr arena, SourceLocation loc, + const ParenContents& paren_contents) -> Ptr { + return arena->New( loc, paren_contents.TupleElements(loc)); } diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index 76e864665489..1436e61e71df 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -13,6 +13,7 @@ #include "common/ostream.h" #include "executable_semantics/ast/paren_contents.h" #include "executable_semantics/ast/source_location.h" +#include "executable_semantics/common/arena.h" #include "llvm/Support/Compiler.h" namespace Carbon { @@ -62,14 +63,14 @@ class Expression { // grouping if their contents permit that interpretation, or as forming a // tuple otherwise. auto ExpressionFromParenContents( - SourceLocation loc, const ParenContents& paren_contents) - -> Ptr; + Ptr arena, SourceLocation loc, + const ParenContents& paren_contents) -> Ptr; // Converts paren_contents to an Expression, interpreting the parentheses as // forming a tuple. auto TupleExpressionFromParenContents( - SourceLocation loc, const ParenContents& paren_contents) - -> Ptr; + Ptr arena, SourceLocation loc, + const ParenContents& paren_contents) -> Ptr; // A FieldInitializer represents the initialization of a single tuple field. struct FieldInitializer { diff --git a/executable_semantics/ast/expression_test.cpp b/executable_semantics/ast/expression_test.cpp index 5248a0059ddf..aca62b65f4b9 100644 --- a/executable_semantics/ast/expression_test.cpp +++ b/executable_semantics/ast/expression_test.cpp @@ -30,27 +30,32 @@ static auto FakeSourceLoc(int line_num) -> SourceLocation { return SourceLocation("", line_num); } -TEST(ExpressionTest, EmptyAsExpression) { +class ExpressionTest : public ::testing::Test { + protected: + Arena arena; +}; + +TEST_F(ExpressionTest, EmptyAsExpression) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; Ptr expression = - ExpressionFromParenContents(FakeSourceLoc(1), contents); + ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).Fields(), IsEmpty()); } -TEST(ExpressionTest, EmptyAsTuple) { +TEST_F(ExpressionTest, EmptyAsTuple) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; - Ptr tuple = - TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + Ptr tuple = TupleExpressionFromParenContents( + PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), IsEmpty()); } -TEST(ExpressionTest, UnaryNoCommaAsExpression) { +TEST_F(ExpressionTest, UnaryNoCommaAsExpression) { // Equivalent to a code fragment like // ``` // ( @@ -59,91 +64,83 @@ TEST(ExpressionTest, UnaryNoCommaAsExpression) { // ``` ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(2), 42)}}, + .term = arena.New(FakeSourceLoc(2), 42)}}, .has_trailing_comma = false}; Ptr expression = - ExpressionFromParenContents(FakeSourceLoc(1), contents); + ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(2)); ASSERT_EQ(expression->Tag(), Expression::Kind::IntLiteral); } -TEST(ExpressionTest, UnaryNoCommaAsTuple) { +TEST_F(ExpressionTest, UnaryNoCommaAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(2), 42)}}, + .term = arena.New(FakeSourceLoc(2), 42)}}, .has_trailing_comma = false}; - Ptr tuple = - TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + Ptr tuple = TupleExpressionFromParenContents( + PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), ElementsAre(IntFieldNamed("0"))); } -TEST(ExpressionTest, UnaryWithCommaAsExpression) { +TEST_F(ExpressionTest, UnaryWithCommaAsExpression) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(2), 42)}}, + .term = arena.New(FakeSourceLoc(2), 42)}}, .has_trailing_comma = true}; Ptr expression = - ExpressionFromParenContents(FakeSourceLoc(1), contents); + ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).Fields(), ElementsAre(IntFieldNamed("0"))); } -TEST(ExpressionTest, UnaryWithCommaAsTuple) { +TEST_F(ExpressionTest, UnaryWithCommaAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(2), 42)}}, + .term = arena.New(FakeSourceLoc(2), 42)}}, .has_trailing_comma = true}; - Ptr tuple = - TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + Ptr tuple = TupleExpressionFromParenContents( + PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), ElementsAre(IntFieldNamed("0"))); } -TEST(ExpressionTest, BinaryAsExpression) { +TEST_F(ExpressionTest, BinaryAsExpression) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(2), 42)}, + .term = arena.New(FakeSourceLoc(2), 42)}, {.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(3), 42)}}, + .term = arena.New(FakeSourceLoc(3), 42)}}, .has_trailing_comma = true}; Ptr expression = - ExpressionFromParenContents(FakeSourceLoc(1), contents); + ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*expression).Fields(), ElementsAre(IntFieldNamed("0"), IntFieldNamed("1"))); } -TEST(ExpressionTest, BinaryAsTuple) { +TEST_F(ExpressionTest, BinaryAsTuple) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(2), 42)}, + .term = arena.New(FakeSourceLoc(2), 42)}, {.name = std::nullopt, - .term = - global_arena->New(FakeSourceLoc(3), 42)}}, + .term = arena.New(FakeSourceLoc(3), 42)}}, .has_trailing_comma = true}; - Ptr tuple = - TupleExpressionFromParenContents(FakeSourceLoc(1), contents); + Ptr tuple = TupleExpressionFromParenContents( + PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral); EXPECT_THAT(cast(*tuple).Fields(), diff --git a/executable_semantics/ast/pattern.cpp b/executable_semantics/ast/pattern.cpp index f64ec2b4312f..71dbece724cd 100644 --- a/executable_semantics/ast/pattern.cpp +++ b/executable_semantics/ast/pattern.cpp @@ -54,30 +54,31 @@ void Pattern::Print(llvm::raw_ostream& out) const { } } -TuplePattern::TuplePattern(Ptr tuple_literal) +TuplePattern::TuplePattern(Ptr arena, + Ptr tuple_literal) : Pattern(Kind::TuplePattern, tuple_literal->SourceLoc()) { const auto& tuple = cast(*tuple_literal); for (const FieldInitializer& init : tuple.Fields()) { - fields.push_back(Field( - init.name, global_arena->New(init.expression))); + fields.push_back( + Field(init.name, arena->New(init.expression))); } } -auto PatternFromParenContents(SourceLocation loc, +auto PatternFromParenContents(Ptr arena, SourceLocation loc, const ParenContents& paren_contents) -> Ptr { std::optional> single_term = paren_contents.SingleTerm(); if (single_term.has_value()) { return *single_term; } else { - return TuplePatternFromParenContents(loc, paren_contents); + return TuplePatternFromParenContents(arena, loc, paren_contents); } } -auto TuplePatternFromParenContents(SourceLocation loc, +auto TuplePatternFromParenContents(Ptr arena, SourceLocation loc, const ParenContents& paren_contents) -> Ptr { - return global_arena->New( + return arena->New( loc, paren_contents.TupleElements(loc)); } @@ -101,14 +102,15 @@ AlternativePattern::AlternativePattern(SourceLocation loc, alternative_name(RequireFieldAccess(alternative).Field()), arguments(arguments) {} -auto ParenExpressionToParenPattern(const ParenContents& contents) +auto ParenExpressionToParenPattern(Ptr arena, + const ParenContents& contents) -> ParenContents { ParenContents result = { .elements = {}, .has_trailing_comma = contents.has_trailing_comma}; for (const auto& element : contents.elements) { result.elements.push_back( {.name = element.name, - .term = global_arena->New(element.term)}); + .term = arena->New(element.term)}); } return result; } diff --git a/executable_semantics/ast/pattern.h b/executable_semantics/ast/pattern.h index 98048934bff3..e7da63b10fea 100644 --- a/executable_semantics/ast/pattern.h +++ b/executable_semantics/ast/pattern.h @@ -111,7 +111,7 @@ class TuplePattern : public Pattern { // ExpressionPattern. // // REQUIRES: tuple_literal->Tag() == Expression::Kind::TupleLiteral - explicit TuplePattern(Ptr tuple_literal); + TuplePattern(Ptr arena, Ptr tuple_literal); static auto classof(const Pattern* pattern) -> bool { return pattern->Tag() == Kind::TuplePattern; @@ -126,19 +126,20 @@ class TuplePattern : public Pattern { // Converts paren_contents to a Pattern, interpreting the parentheses as // grouping if their contents permit that interpretation, or as forming a // tuple otherwise. -auto PatternFromParenContents(SourceLocation loc, +auto PatternFromParenContents(Ptr arena, SourceLocation loc, const ParenContents& paren_contents) -> Ptr; // Converts paren_contents to a TuplePattern, interpreting the parentheses as // forming a tuple. -auto TuplePatternFromParenContents(SourceLocation loc, +auto TuplePatternFromParenContents(Ptr arena, SourceLocation loc, const ParenContents& paren_contents) -> Ptr; // Converts `contents` to ParenContents by replacing each Expression // with an ExpressionPattern. -auto ParenExpressionToParenPattern(const ParenContents& contents) +auto ParenExpressionToParenPattern(Ptr arena, + const ParenContents& contents) -> ParenContents; // A pattern that matches an alternative of a choice type. diff --git a/executable_semantics/ast/pattern_test.cpp b/executable_semantics/ast/pattern_test.cpp index 3975486a5824..5f8d5bbfd329 100644 --- a/executable_semantics/ast/pattern_test.cpp +++ b/executable_semantics/ast/pattern_test.cpp @@ -29,26 +29,31 @@ static auto FakeSourceLoc(int line_num) -> SourceLocation { return SourceLocation("", line_num); } -TEST(PatternTest, EmptyAsPattern) { +class PatternTest : public ::testing::Test { + protected: + Arena arena; +}; + +TEST_F(PatternTest, EmptyAsPattern) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; Ptr pattern = - PatternFromParenContents(FakeSourceLoc(1), contents); + PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(*pattern)); EXPECT_THAT(cast(*pattern).Fields(), IsEmpty()); } -TEST(PatternTest, EmptyAsTuplePattern) { +TEST_F(PatternTest, EmptyAsTuplePattern) { ParenContents contents = {.elements = {}, .has_trailing_comma = false}; Ptr tuple = - TuplePatternFromParenContents(FakeSourceLoc(1), contents); + TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), IsEmpty()); } -TEST(PatternTest, UnaryNoCommaAsPattern) { +TEST_F(PatternTest, UnaryNoCommaAsPattern) { // Equivalent to a code fragment like // ``` // ( @@ -57,79 +62,79 @@ TEST(PatternTest, UnaryNoCommaAsPattern) { // ``` ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}}, + .term = arena.New(FakeSourceLoc(2))}}, .has_trailing_comma = false}; Ptr pattern = - PatternFromParenContents(FakeSourceLoc(1), contents); + PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(2)); ASSERT_TRUE(isa(*pattern)); } -TEST(PatternTest, UnaryNoCommaAsTuplePattern) { +TEST_F(PatternTest, UnaryNoCommaAsTuplePattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}}, + .term = arena.New(FakeSourceLoc(2))}}, .has_trailing_comma = false}; Ptr tuple = - TuplePatternFromParenContents(FakeSourceLoc(1), contents); + TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"))); } -TEST(PatternTest, UnaryWithCommaAsPattern) { +TEST_F(PatternTest, UnaryWithCommaAsPattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}}, + .term = arena.New(FakeSourceLoc(2))}}, .has_trailing_comma = true}; Ptr pattern = - PatternFromParenContents(FakeSourceLoc(1), contents); + PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(*pattern)); EXPECT_THAT(cast(*pattern).Fields(), ElementsAre(AutoFieldNamed("0"))); } -TEST(PatternTest, UnaryWithCommaAsTuplePattern) { +TEST_F(PatternTest, UnaryWithCommaAsTuplePattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}}, + .term = arena.New(FakeSourceLoc(2))}}, .has_trailing_comma = true}; Ptr tuple = - TuplePatternFromParenContents(FakeSourceLoc(1), contents); + TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"))); } -TEST(PatternTest, BinaryAsPattern) { +TEST_F(PatternTest, BinaryAsPattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}, + .term = arena.New(FakeSourceLoc(2))}, {.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}}, + .term = arena.New(FakeSourceLoc(2))}}, .has_trailing_comma = true}; Ptr pattern = - PatternFromParenContents(FakeSourceLoc(1), contents); + PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1)); ASSERT_TRUE(isa(*pattern)); EXPECT_THAT(cast(*pattern).Fields(), ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1"))); } -TEST(PatternTest, BinaryAsTuplePattern) { +TEST_F(PatternTest, BinaryAsTuplePattern) { ParenContents contents = { .elements = {{.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}, + .term = arena.New(FakeSourceLoc(2))}, {.name = std::nullopt, - .term = global_arena->New(FakeSourceLoc(2))}}, + .term = arena.New(FakeSourceLoc(2))}}, .has_trailing_comma = true}; Ptr tuple = - TuplePatternFromParenContents(FakeSourceLoc(1), contents); + TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents); EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1)); EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1"))); diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h index c94cdb4c35cd..5baba4040f45 100644 --- a/executable_semantics/ast/statement.h +++ b/executable_semantics/ast/statement.h @@ -135,8 +135,8 @@ class If : public Statement { class Return : public Statement { public: - explicit Return(SourceLocation loc) - : Return(loc, global_arena->New(loc), true) {} + Return(Ptr arena, SourceLocation loc) + : Return(loc, arena->New(loc), true) {} Return(SourceLocation loc, Ptr exp, bool is_omitted_exp) : Statement(Kind::Return, loc), exp(exp), diff --git a/executable_semantics/common/BUILD b/executable_semantics/common/BUILD index d7e11fe48ced..d5f5d1dbf1a8 100644 --- a/executable_semantics/common/BUILD +++ b/executable_semantics/common/BUILD @@ -6,11 +6,9 @@ package(default_visibility = ["//executable_semantics:__subpackages__"]) cc_library( name = "arena", - srcs = ["arena.cpp"], hdrs = ["arena.h"], deps = [ ":ptr", - "@llvm-project//llvm:Support", ], ) diff --git a/executable_semantics/common/arena.cpp b/executable_semantics/common/arena.cpp deleted file mode 100644 index 58b3f409a134..000000000000 --- a/executable_semantics/common/arena.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// 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 - -#include "executable_semantics/common/arena.h" - -namespace Carbon { - -llvm::ManagedStatic global_arena; - -} // namespace Carbon diff --git a/executable_semantics/common/arena.h b/executable_semantics/common/arena.h index 6c1774171568..7f52b7d2a906 100644 --- a/executable_semantics/common/arena.h +++ b/executable_semantics/common/arena.h @@ -9,7 +9,6 @@ #include #include "executable_semantics/common/ptr.h" -#include "llvm/Support/ManagedStatic.h" namespace Carbon { @@ -51,8 +50,6 @@ class Arena { std::vector> arena; }; -extern llvm::ManagedStatic global_arena; - } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_COMMON_ARENA_H_ diff --git a/executable_semantics/common/ptr.h b/executable_semantics/common/ptr.h index ccb053c8e970..6960ca67ffa1 100644 --- a/executable_semantics/common/ptr.h +++ b/executable_semantics/common/ptr.h @@ -39,6 +39,11 @@ class Ptr { T* ptr; }; +template +auto PtrTo(T& obj) -> Ptr { + return Ptr(&obj); +} + } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_COMMON_PTR_H_ diff --git a/executable_semantics/interpreter/dictionary.h b/executable_semantics/interpreter/dictionary.h index 258730f3df21..032adf3fbff8 100644 --- a/executable_semantics/interpreter/dictionary.h +++ b/executable_semantics/interpreter/dictionary.h @@ -60,7 +60,7 @@ class Dictionary { }; // Create an empty dictionary. - Dictionary() {} + explicit Dictionary(Ptr arena) : arena(arena) {} // Return the value associated with the given key. // Time complexity: O(n) where n is the number of times @@ -77,7 +77,7 @@ class Dictionary { // Associate the value v with key k in the dictionary. // Time complexity: O(1). auto Set(const K& k, const V& v) -> void { - head = global_arena->New(std::make_pair(k, v), head); + head = arena->New(std::make_pair(k, v), head); } bool IsEmpty() { return !head; } @@ -91,6 +91,7 @@ class Dictionary { private: std::optional> head; + Ptr arena; }; } // namespace Carbon diff --git a/executable_semantics/interpreter/exec_program.cpp b/executable_semantics/interpreter/exec_program.cpp index 90bd42e15d2c..6a496cacc3dd 100644 --- a/executable_semantics/interpreter/exec_program.cpp +++ b/executable_semantics/interpreter/exec_program.cpp @@ -15,30 +15,29 @@ namespace Carbon { // Adds builtins, currently only Print(). Note Print() is experimental, not // standardized, but is made available for printing state in tests. -static void AddIntrinsics(std::vector>* declarations) { +static void AddIntrinsics(Ptr arena, + std::vector>* declarations) { SourceLocation loc("", 0); std::vector print_fields = {TuplePattern::Field( - "0", global_arena->New( - loc, "format_str", - global_arena->New( - global_arena->New(loc))))}; + "0", + arena->New( + loc, "format_str", + arena->New(arena->New(loc))))}; auto print_return = - global_arena->New(loc, - global_arena->New( - IntrinsicExpression::IntrinsicKind::Print), - false); - auto print = global_arena->New( - global_arena->New( - loc, "Print", std::vector(), - global_arena->New(loc, print_fields), - global_arena->New( - global_arena->New(loc)), - /*is_omitted_return_type=*/false, print_return)); + arena->New(loc, + arena->New( + IntrinsicExpression::IntrinsicKind::Print), + false); + auto print = arena->New(arena->New( + loc, "Print", std::vector(), + arena->New(loc, print_fields), + arena->New(arena->New(loc)), + /*is_omitted_return_type=*/false, print_return)); declarations->insert(declarations->begin(), print); } -void ExecProgram(AST ast) { - AddIntrinsics(&ast.declarations); +void ExecProgram(Ptr arena, AST ast) { + AddIntrinsics(arena, &ast.declarations); if (tracing_output) { llvm::outs() << "********** source program **********\n"; for (const auto decl : ast.declarations) { @@ -46,7 +45,7 @@ void ExecProgram(AST ast) { } llvm::outs() << "********** type checking **********\n"; } - TypeChecker type_checker; + TypeChecker type_checker(arena); TypeChecker::TypeCheckContext p = type_checker.TopLevel(ast.declarations); TypeEnv top = p.types; Env ct_top = p.values; @@ -62,7 +61,7 @@ void ExecProgram(AST ast) { } llvm::outs() << "********** starting execution **********\n"; } - int result = Interpreter().InterpProgram(new_decls); + int result = Interpreter(arena).InterpProgram(new_decls); llvm::outs() << "result: " << result << "\n"; } diff --git a/executable_semantics/interpreter/exec_program.h b/executable_semantics/interpreter/exec_program.h index 51b3e6aca709..3e837763f58a 100644 --- a/executable_semantics/interpreter/exec_program.h +++ b/executable_semantics/interpreter/exec_program.h @@ -14,7 +14,7 @@ namespace Carbon { // Runs the top-level declaration list. -void ExecProgram(AST ast); +void ExecProgram(Ptr arena, AST ast); } // namespace Carbon diff --git a/executable_semantics/interpreter/heap.cpp b/executable_semantics/interpreter/heap.cpp index a0a02399b80b..8f68d3251b44 100644 --- a/executable_semantics/interpreter/heap.cpp +++ b/executable_semantics/interpreter/heap.cpp @@ -14,33 +14,33 @@ auto Heap::AllocateValue(Ptr v) -> Address { // ensures that we don't do anything else in between, which is really bad! // Consider whether to include a copy of the input v in this function // or to leave it up to the caller. - Address a(values_.size()); - values_.push_back(v); - alive_.push_back(true); + Address a(values.size()); + values.push_back(v); + alive.push_back(true); return a; } auto Heap::Read(const Address& a, SourceLocation loc) -> Ptr { this->CheckAlive(a, loc); - return values_[a.index]->GetField(a.field_path, loc); + return values[a.index]->GetField(arena, a.field_path, loc); } void Heap::Write(const Address& a, Ptr v, SourceLocation loc) { this->CheckAlive(a, loc); - values_[a.index] = values_[a.index]->SetField(a.field_path, v, loc); + values[a.index] = values[a.index]->SetField(arena, a.field_path, v, loc); } void Heap::CheckAlive(const Address& address, SourceLocation loc) { - if (!alive_[address.index]) { + if (!alive[address.index]) { FATAL_RUNTIME_ERROR(loc) << "undefined behavior: access to dead value " - << *values_[address.index]; + << *values[address.index]; } } void Heap::Deallocate(const Address& address) { CHECK(address.field_path.IsEmpty()); - if (alive_[address.index]) { - alive_[address.index] = false; + if (alive[address.index]) { + alive[address.index] = false; } else { FATAL_RUNTIME_ERROR_NO_LINE() << "deallocating an already dead value"; } @@ -48,17 +48,17 @@ void Heap::Deallocate(const Address& address) { void Heap::Print(llvm::raw_ostream& out) const { llvm::ListSeparator sep; - for (size_t i = 0; i < values_.size(); ++i) { + for (size_t i = 0; i < values.size(); ++i) { out << sep; PrintAddress(Address(i), out); } } void Heap::PrintAddress(const Address& a, llvm::raw_ostream& out) const { - if (!alive_[a.index]) { + if (!alive[a.index]) { out << "!!"; } - out << *values_[a.index]; + out << *values[a.index]; } } // namespace Carbon diff --git a/executable_semantics/interpreter/heap.h b/executable_semantics/interpreter/heap.h index 3e8c523af220..30ba4956ff7d 100644 --- a/executable_semantics/interpreter/heap.h +++ b/executable_semantics/interpreter/heap.h @@ -18,7 +18,7 @@ namespace Carbon { class Heap { public: // Constructs an empty Heap. - Heap() = default; + explicit Heap(Ptr arena) : arena(arena){}; Heap(const Heap&) = delete; Heap& operator=(const Heap&) = delete; @@ -49,8 +49,9 @@ class Heap { // Signal an error if the address is no longer alive. void CheckAlive(const Address& address, SourceLocation loc); - std::vector> values_; - std::vector alive_; + Ptr arena; + std::vector> values; + std::vector alive; }; } // namespace Carbon diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index 6e4936fa86f3..0bc96f52af7c 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -74,32 +74,33 @@ void Interpreter::PrintState(llvm::raw_ostream& out) { out << "\n}\n"; } -static auto EvalPrim(Operator op, const std::vector>& args, - SourceLocation loc) -> Ptr { +auto Interpreter::EvalPrim(Operator op, + const std::vector>& args, + SourceLocation loc) -> Ptr { switch (op) { case Operator::Neg: - return global_arena->New(-cast(*args[0]).Val()); + return arena->New(-cast(*args[0]).Val()); case Operator::Add: - return global_arena->New(cast(*args[0]).Val() + - cast(*args[1]).Val()); + return arena->New(cast(*args[0]).Val() + + cast(*args[1]).Val()); case Operator::Sub: - return global_arena->New(cast(*args[0]).Val() - - cast(*args[1]).Val()); + return arena->New(cast(*args[0]).Val() - + cast(*args[1]).Val()); case Operator::Mul: - return global_arena->New(cast(*args[0]).Val() * - cast(*args[1]).Val()); + return arena->New(cast(*args[0]).Val() * + cast(*args[1]).Val()); case Operator::Not: - return global_arena->New(!cast(*args[0]).Val()); + return arena->New(!cast(*args[0]).Val()); case Operator::And: - return global_arena->New(cast(*args[0]).Val() && - cast(*args[1]).Val()); + return arena->New(cast(*args[0]).Val() && + cast(*args[1]).Val()); case Operator::Or: - return global_arena->New(cast(*args[0]).Val() || - cast(*args[1]).Val()); + return arena->New(cast(*args[0]).Val() || + cast(*args[1]).Val()); case Operator::Eq: - return global_arena->New(ValueEqual(args[0], args[1], loc)); + return arena->New(ValueEqual(args[0], args[1], loc)); case Operator::Ptr: - return global_arena->New(args[0]); + return arena->New(args[0]); case Operator::Deref: FATAL() << "dereference not implemented yet"; } @@ -113,13 +114,11 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) { Env new_env = *env; // Bring the deduced parameters into scope. for (const auto& deduced : func_def.deduced_parameters) { - Address a = - heap.AllocateValue(global_arena->New(deduced.name)); + Address a = heap.AllocateValue(arena->New(deduced.name)); new_env.Set(deduced.name, a); } auto pt = InterpPattern(new_env, func_def.param_pattern); - auto f = - global_arena->New(func_def.name, pt, func_def.body); + auto f = arena->New(func_def.name, pt, func_def.body); Address a = heap.AllocateValue(f); env->Set(func_def.name, a); break; @@ -135,14 +134,14 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) { Ptr binding = cast(*m).Binding(); Ptr type_expression = cast(*binding->Type()).Expression(); - auto type = InterpExp(Env(), type_expression); + auto type = InterpExp(Env(arena), type_expression); fields.push_back(make_pair(*binding->Name(), type)); break; } } } - auto st = global_arena->New(class_def.name, std::move(fields), - std::move(methods)); + auto st = arena->New(class_def.name, std::move(fields), + std::move(methods)); auto a = heap.AllocateValue(st); env->Set(class_def.name, a); break; @@ -152,10 +151,10 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) { const auto& choice = cast(d); VarValues alts; for (const auto& [name, signature] : choice.Alternatives()) { - auto t = InterpExp(Env(), signature); + auto t = InterpExp(Env(arena), signature); alts.push_back(make_pair(name, t)); } - auto ct = global_arena->New(choice.Name(), std::move(alts)); + auto ct = arena->New(choice.Name(), std::move(alts)); auto a = heap.AllocateValue(ct); env->Set(choice.Name(), a); break; @@ -194,8 +193,8 @@ void Interpreter::DeallocateLocals(Ptr frame) { } } -static Ptr CreateTuple(Ptr act, - Ptr exp) { +auto Interpreter::CreateTuple(Ptr act, Ptr exp) + -> Ptr { // { { (v1,...,vn) :: C, E, F} :: S, H} // -> { { `(v1,...,vn) :: C, E, F} :: S, H} const auto& tup_lit = cast(*exp); @@ -206,7 +205,7 @@ static Ptr CreateTuple(Ptr act, {.name = tup_lit.Fields()[i].name, .value = act->Results()[i]}); } - return global_arena->New(std::move(elements)); + return arena->New(std::move(elements)); } auto Interpreter::PatternMatch(Ptr p, Ptr v, @@ -214,9 +213,9 @@ auto Interpreter::PatternMatch(Ptr p, Ptr v, switch (p->Tag()) { case Value::Kind::BindingPlaceholderValue: { const auto& placeholder = cast(*p); - Env values; + Env values(arena); if (placeholder.Name().has_value()) { - Address a = heap.AllocateValue(CopyVal(v, loc)); + Address a = heap.AllocateValue(CopyVal(arena, v, loc)); values.Set(*placeholder.Name(), a); } return values; @@ -231,7 +230,7 @@ auto Interpreter::PatternMatch(Ptr p, Ptr v, << "arity mismatch in tuple pattern match:\n pattern: " << p_tup << "\n value: " << v_tup; } - Env values; + Env values(arena); for (size_t i = 0; i < p_tup.Elements().size(); ++i) { if (p_tup.Elements()[i].name != v_tup.Elements()[i].name) { FATAL_PROGRAM_ERROR(loc) @@ -294,10 +293,10 @@ auto Interpreter::PatternMatch(Ptr p, Ptr v, case Value::Kind::AutoType: // `auto` matches any type, without binding any new names. We rely // on the typechecker to ensure that `v` is a type. - return Env(); + return Env(arena); default: if (ValueEqual(p, v, loc)) { - return Env(); + return Env(arena); } else { return std::nullopt; } @@ -308,7 +307,7 @@ void Interpreter::PatternAssignment(Ptr pat, Ptr val, SourceLocation loc) { switch (pat->Tag()) { case Value::Kind::PointerValue: - heap.Write(cast(*pat).Val(), CopyVal(val, loc), loc); + heap.Write(cast(*pat).Val(), CopyVal(arena, val, loc), loc); break; case Value::Kind::TupleValue: { switch (val->Tag()) { @@ -371,14 +370,14 @@ auto Interpreter::StepLvalue() -> Transition { // -> { {E(x) :: C, E, F} :: S, H} Address pointer = GetFromEnv(exp->SourceLoc(), cast(*exp).Name()); - Ptr v = global_arena->New(pointer); + Ptr v = arena->New(pointer); return Done{v}; } case Expression::Kind::FieldAccessExpression: { if (act->Pos() == 0) { // { {e.f :: C, E, F} :: S, H} // -> { e :: [].f :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*exp).Aggregate())}; } else { // { v :: [].f :: C, E, F} :: S, H} @@ -386,19 +385,19 @@ auto Interpreter::StepLvalue() -> Transition { Address aggregate = cast(*act->Results()[0]).Val(); Address field = aggregate.SubobjectAddress( cast(*exp).Field()); - return Done{global_arena->New(field)}; + return Done{arena->New(field)}; } } case Expression::Kind::IndexExpression: { if (act->Pos() == 0) { // { {e[i] :: C, E, F} :: S, H} // -> { e :: [][i] :: C, E, F} :: S, H} - return Spawn{global_arena->New( - cast(*exp).Aggregate())}; + return Spawn{ + arena->New(cast(*exp).Aggregate())}; } else if (act->Pos() == 1) { - return Spawn{global_arena->New( - cast(*exp).Offset())}; + return Spawn{ + arena->New(cast(*exp).Offset())}; } else { // { v :: [][i] :: C, E, F} :: S, H} // -> { { &v[i] :: C, E, F} :: S, H } @@ -406,7 +405,7 @@ auto Interpreter::StepLvalue() -> Transition { std::string f = std::to_string(cast(*act->Results()[1]).Val()); Address field = aggregate.SubobjectAddress(f); - return Done{global_arena->New(field)}; + return Done{arena->New(field)}; } } case Expression::Kind::TupleLiteral: { @@ -415,7 +414,7 @@ auto Interpreter::StepLvalue() -> Transition { // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} Ptr e1 = cast(*exp).Fields()[0].expression; - return Spawn{global_arena->New(e1)}; + return Spawn{arena->New(e1)}; } else if (act->Pos() != static_cast(cast(*exp).Fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, @@ -424,7 +423,7 @@ auto Interpreter::StepLvalue() -> Transition { // H} Ptr elt = cast(*exp).Fields()[act->Pos()].expression; - return Spawn{global_arena->New(elt)}; + return Spawn{arena->New(elt)}; } else { return Done{CreateTuple(act, exp)}; } @@ -458,11 +457,11 @@ auto Interpreter::StepExp() -> Transition { if (act->Pos() == 0) { // { { e[i] :: C, E, F} :: S, H} // -> { { e :: [][i] :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*exp).Aggregate())}; } else if (act->Pos() == 1) { - return Spawn{global_arena->New( - cast(*exp).Offset())}; + return Spawn{ + arena->New(cast(*exp).Offset())}; } else { // { { v :: [][i] :: C, E, F} :: S, H} // -> { { v_i :: C, E, F} : S, H} @@ -488,7 +487,7 @@ auto Interpreter::StepExp() -> Transition { // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H} Ptr e1 = cast(*exp).Fields()[0].expression; - return Spawn{global_arena->New(e1)}; + return Spawn{arena->New(e1)}; } else { return Done{CreateTuple(act, exp)}; } @@ -500,7 +499,7 @@ auto Interpreter::StepExp() -> Transition { // H} Ptr elt = cast(*exp).Fields()[act->Pos()].expression; - return Spawn{global_arena->New(elt)}; + return Spawn{arena->New(elt)}; } else { return Done{CreateTuple(act, exp)}; } @@ -510,12 +509,12 @@ auto Interpreter::StepExp() -> Transition { if (act->Pos() == 0) { // { { e.f :: C, E, F} :: S, H} // -> { { e :: [].f :: C, E, F} :: S, H} - return Spawn{global_arena->New(access.Aggregate())}; + return Spawn{arena->New(access.Aggregate())}; } else { // { { v :: [].f :: C, E, F} :: S, H} // -> { { v_f :: C, E, F} : S, H} - return Done{act->Results()[0]->GetField(FieldPath(access.Field()), - exp->SourceLoc())}; + return Done{act->Results()[0]->GetField( + arena, FieldPath(access.Field()), exp->SourceLoc())}; } } case Expression::Kind::IdentifierExpression: { @@ -528,18 +527,18 @@ auto Interpreter::StepExp() -> Transition { case Expression::Kind::IntLiteral: CHECK(act->Pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} - return Done{global_arena->New(cast(*exp).Val())}; + return Done{arena->New(cast(*exp).Val())}; case Expression::Kind::BoolLiteral: CHECK(act->Pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} - return Done{global_arena->New(cast(*exp).Val())}; + return Done{arena->New(cast(*exp).Val())}; case Expression::Kind::PrimitiveOperatorExpression: { const auto& op = cast(*exp); if (act->Pos() != static_cast(op.Arguments().size())) { // { {v :: op(vs,[],e,es) :: C, E, F} :: S, H} // -> { {e :: op(vs,v,[],es) :: C, E, F} :: S, H} Ptr arg = op.Arguments()[act->Pos()]; - return Spawn{global_arena->New(arg)}; + return Spawn{arena->New(arg)}; } else { // { {v :: op(vs,[]) :: C, E, F} :: S, H} // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H} @@ -550,27 +549,29 @@ auto Interpreter::StepExp() -> Transition { if (act->Pos() == 0) { // { {e1(e2) :: C, E, F} :: S, H} // -> { {e1 :: [](e2) :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*exp).Function())}; } else if (act->Pos() == 1) { // { { v :: [](e) :: C, E, F} :: S, H} // -> { { e :: v([]) :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*exp).Argument())}; } else if (act->Pos() == 2) { // { { v2 :: v1([]) :: C, E, F} :: S, H} // -> { {C',E',F'} :: {C, E, F} :: S, H} switch (act->Results()[0]->Tag()) { case Value::Kind::ClassType: { - Ptr arg = CopyVal(act->Results()[1], exp->SourceLoc()); - return Done{global_arena->New(act->Results()[0], arg)}; + Ptr arg = + CopyVal(arena, act->Results()[1], exp->SourceLoc()); + return Done{arena->New(act->Results()[0], arg)}; } case Value::Kind::AlternativeConstructorValue: { const auto& alt = cast(*act->Results()[0]); - Ptr arg = CopyVal(act->Results()[1], exp->SourceLoc()); - return Done{global_arena->New( - alt.AltName(), alt.ChoiceName(), arg)}; + Ptr arg = + CopyVal(arena, act->Results()[1], exp->SourceLoc()); + return Done{arena->New(alt.AltName(), + alt.ChoiceName(), arg)}; } case Value::Kind::FunctionValue: return CallFunction{ @@ -602,45 +603,44 @@ auto Interpreter::StepExp() -> Transition { case Expression::Kind::IntTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->New()}; + return Done{arena->New()}; } case Expression::Kind::BoolTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->New()}; + return Done{arena->New()}; } case Expression::Kind::TypeTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->New()}; + return Done{arena->New()}; } case Expression::Kind::FunctionTypeLiteral: { if (act->Pos() == 0) { - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*exp).Parameter())}; } else if (act->Pos() == 1) { // { { pt :: fn [] -> e :: C, E, F} :: S, H} // -> { { e :: fn pt -> []) :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*exp).ReturnType())}; } else { // { { rt :: fn pt -> [] :: C, E, F} :: S, H} // -> { fn pt -> rt :: {C, E, F} :: S, H} - return Done{global_arena->New( - std::vector(), act->Results()[0], - act->Results()[1])}; + return Done{arena->New(std::vector(), + act->Results()[0], + act->Results()[1])}; } } case Expression::Kind::ContinuationTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->New()}; + return Done{arena->New()}; } case Expression::Kind::StringLiteral: CHECK(act->Pos() == 0); // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} - return Done{ - global_arena->New(cast(*exp).Val())}; + return Done{arena->New(cast(*exp).Val())}; case Expression::Kind::StringTypeLiteral: { CHECK(act->Pos() == 0); - return Done{global_arena->New()}; + return Done{arena->New()}; } } // switch (exp->Tag) } @@ -655,15 +655,15 @@ auto Interpreter::StepPattern() -> Transition { switch (pattern->Tag()) { case Pattern::Kind::AutoPattern: { CHECK(act->Pos() == 0); - return Done{global_arena->New()}; + return Done{arena->New()}; } case Pattern::Kind::BindingPattern: { const auto& binding = cast(*pattern); if (act->Pos() == 0) { - return Spawn{global_arena->New(binding.Type())}; + return Spawn{arena->New(binding.Type())}; } else { - return Done{global_arena->New( - binding.Name(), act->Results()[0])}; + return Done{arena->New(binding.Name(), + act->Results()[0])}; } } case Pattern::Kind::TuplePattern: { @@ -673,7 +673,7 @@ auto Interpreter::StepPattern() -> Transition { return Done{TupleValue::Empty()}; } else { Ptr p1 = tuple.Fields()[0].pattern; - return Spawn{(global_arena->New(p1))}; + return Spawn{(arena->New(p1))}; } } else if (act->Pos() != static_cast(tuple.Fields().size())) { // { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S, @@ -681,33 +681,32 @@ auto Interpreter::StepPattern() -> Transition { // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S, // H} Ptr elt = tuple.Fields()[act->Pos()].pattern; - return Spawn{global_arena->New(elt)}; + return Spawn{arena->New(elt)}; } else { std::vector elements; for (size_t i = 0; i < tuple.Fields().size(); ++i) { elements.push_back( {.name = tuple.Fields()[i].name, .value = act->Results()[i]}); } - return Done{global_arena->New(std::move(elements))}; + return Done{arena->New(std::move(elements))}; } } case Pattern::Kind::AlternativePattern: { const auto& alternative = cast(*pattern); if (act->Pos() == 0) { - return Spawn{ - global_arena->New(alternative.ChoiceType())}; + return Spawn{arena->New(alternative.ChoiceType())}; } else if (act->Pos() == 1) { - return Spawn{global_arena->New(alternative.Arguments())}; + return Spawn{arena->New(alternative.Arguments())}; } else { CHECK(act->Pos() == 2); const auto& choice_type = cast(*act->Results()[0]); - return Done{global_arena->New( - alternative.AlternativeName(), choice_type.Name(), - act->Results()[1])}; + return Done{arena->New(alternative.AlternativeName(), + choice_type.Name(), + act->Results()[1])}; } } case Pattern::Kind::ExpressionPattern: - return Delegate{global_arena->New( + return Delegate{arena->New( cast(*pattern).Expression())}; } } @@ -756,8 +755,8 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { // { { (match (e) ...) :: C, E, F} :: S, H} // -> { { e :: (match ([]) ...) :: C, E, F} :: S, H} - frame->scopes.Push(global_arena->New(CurrentEnv())); - return Spawn{global_arena->New(match_stmt.Exp())}; + frame->scopes.Push(arena->New(CurrentEnv())); + return Spawn{arena->New(match_stmt.Exp())}; } else { // Regarding act->Pos(): // * odd: start interpreting the pattern of a clause @@ -780,7 +779,7 @@ auto Interpreter::StepStmt() -> Transition { // start interpreting the pattern of the clause // { {v :: (match ([]) ...) :: C, E, F} :: S, H} // -> { {pi :: (match ([]) ...) :: C, E, F} :: S, H} - return Spawn{global_arena->New(c.first)}; + return Spawn{arena->New(c.first)}; } else { // try to match auto v = act->Results()[0]; auto pat = act->Results()[clause_num + 1]; @@ -793,7 +792,7 @@ auto Interpreter::StepStmt() -> Transition { frame->scopes.Top()->values.Set(name, value); frame->scopes.Top()->locals.push_back(name); } - return Spawn{global_arena->New(c.second)}; + return Spawn{arena->New(c.second)}; } else { return RunAgain{}; } @@ -805,13 +804,11 @@ auto Interpreter::StepStmt() -> Transition { // { { (while (e) s) :: C, E, F} :: S, H} // -> { { e :: (while ([]) s) :: C, E, F} :: S, H} act->Clear(); - return Spawn{ - global_arena->New(cast(*stmt).Cond())}; + return Spawn{arena->New(cast(*stmt).Cond())}; } else if (cast(*act->Results().back()).Val()) { // { {true :: (while ([]) s) :: C, E, F} :: S, H} // -> { { s :: (while (e) s) :: C, E, F } :: S, H} - return Spawn{ - global_arena->New(cast(*stmt).Body())}; + return Spawn{arena->New(cast(*stmt).Body())}; } else { // { {false :: (while ([]) s) :: C, E, F} :: S, H} // -> { { C, E, F } :: S, H} @@ -846,8 +843,8 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { const Block& block = cast(*stmt); if (block.Stmt()) { - frame->scopes.Push(global_arena->New(CurrentEnv())); - return Spawn{global_arena->New(*block.Stmt())}; + frame->scopes.Push(arena->New(CurrentEnv())); + return Spawn{arena->New(*block.Stmt())}; } else { return Done{}; } @@ -862,11 +859,11 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { // { {(var x = e) :: C, E, F} :: S, H} // -> { {e :: (var x = []) :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*stmt).Init())}; } else if (act->Pos() == 1) { - return Spawn{global_arena->New( - cast(*stmt).Pat())}; + return Spawn{ + arena->New(cast(*stmt).Pat())}; } else { // { { v :: (x = []) :: C, E, F} :: S, H} // -> { { C, E(x := a), F} :: S, H(a := copy(v))} @@ -887,7 +884,7 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { // { {e :: C, E, F} :: S, H} // -> { {e :: C, E, F} :: S, H} - return Spawn{global_arena->New( + return Spawn{arena->New( cast(*stmt).Exp())}; } else { return Done{}; @@ -896,12 +893,11 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { // { {(lv = e) :: C, E, F} :: S, H} // -> { {lv :: ([] = e) :: C, E, F} :: S, H} - return Spawn{global_arena->New(cast(*stmt).Lhs())}; + return Spawn{arena->New(cast(*stmt).Lhs())}; } else if (act->Pos() == 1) { // { { a :: ([] = e) :: C, E, F} :: S, H} // -> { { e :: (a = []) :: C, E, F} :: S, H} - return Spawn{ - global_arena->New(cast(*stmt).Rhs())}; + return Spawn{arena->New(cast(*stmt).Rhs())}; } else { // { { v :: (a = []) :: C, E, F} :: S, H} // -> { { C, E, F} :: S, H(a := v)} @@ -914,20 +910,19 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { // { {(if (e) then_stmt else else_stmt) :: C, E, F} :: S, H} // -> { { e :: (if ([]) then_stmt else else_stmt) :: C, E, F} :: S, H} - return Spawn{ - global_arena->New(cast(*stmt).Cond())}; + return Spawn{arena->New(cast(*stmt).Cond())}; } else if (cast(*act->Results()[0]).Val()) { // { {true :: if ([]) then_stmt else else_stmt :: C, E, F} :: // S, H} // -> { { then_stmt :: C, E, F } :: S, H} return Delegate{ - global_arena->New(cast(*stmt).ThenStmt())}; + arena->New(cast(*stmt).ThenStmt())}; } else if (cast(*stmt).ElseStmt()) { // { {false :: if ([]) then_stmt else else_stmt :: C, E, F} :: // S, H} // -> { { else_stmt :: C, E, F } :: S, H} return Delegate{ - global_arena->New(*cast(*stmt).ElseStmt())}; + arena->New(*cast(*stmt).ElseStmt())}; } else { return Done{}; } @@ -935,13 +930,12 @@ auto Interpreter::StepStmt() -> Transition { if (act->Pos() == 0) { // { {return e :: C, E, F} :: S, H} // -> { {e :: return [] :: C, E, F} :: S, H} - return Spawn{ - global_arena->New(cast(*stmt).Exp())}; + return Spawn{arena->New(cast(*stmt).Exp())}; } else { // { {v :: return [] :: C, E, F} :: {C', E', F'} :: S, H} // -> { {v :: C', E', F'} :: S, H} Ptr ret_val = - CopyVal(act->Results()[0], stmt->SourceLoc()); + CopyVal(arena, act->Results()[0], stmt->SourceLoc()); return UnwindFunctionCall{ret_val}; } case Statement::Kind::Sequence: { @@ -949,11 +943,11 @@ auto Interpreter::StepStmt() -> Transition { // -> { { s1 :: s2 :: C, E, F} :: S, H} const Sequence& seq = cast(*stmt); if (act->Pos() == 0) { - return Spawn{global_arena->New(seq.Stmt())}; + return Spawn{arena->New(seq.Stmt())}; } else { if (seq.Next()) { - return Delegate{global_arena->New( - *cast(*stmt).Next())}; + return Delegate{ + arena->New(*cast(*stmt).Next())}; } else { return Done{}; } @@ -963,16 +957,15 @@ auto Interpreter::StepStmt() -> Transition { CHECK(act->Pos() == 0); // Create a continuation object by creating a frame similar the // way one is created in a function call. - auto scopes = Stack>(global_arena->New(CurrentEnv())); + auto scopes = Stack>(arena->New(CurrentEnv())); Stack> todo; - todo.Push(global_arena->New( - global_arena->New(stmt->SourceLoc()))); - todo.Push( - global_arena->New(cast(*stmt).Body())); + todo.Push(arena->New( + arena->New(arena, stmt->SourceLoc()))); + todo.Push(arena->New(cast(*stmt).Body())); auto continuation_frame = - global_arena->New("__continuation", scopes, todo); + arena->New("__continuation", scopes, todo); Address continuation_address = - heap.AllocateValue(global_arena->New( + heap.AllocateValue(arena->New( std::vector>({continuation_frame}))); // Store the continuation's address in the frame. continuation_frame->continuation = continuation_address; @@ -987,16 +980,15 @@ auto Interpreter::StepStmt() -> Transition { case Statement::Kind::Run: if (act->Pos() == 0) { // Evaluate the argument of the run statement. - return Spawn{ - global_arena->New(cast(*stmt).Argument())}; + return Spawn{arena->New(cast(*stmt).Argument())}; } else { frame->todo.Pop(1); // Push an expression statement action to ignore the result // value from the continuation. - auto ignore_result = global_arena->New( - global_arena->New( + auto ignore_result = + arena->New(arena->New( stmt->SourceLoc(), - global_arena->New(stmt->SourceLoc()))); + arena->New(stmt->SourceLoc()))); frame->todo.Push(ignore_result); // Push the continuation onto the current stack. const std::vector>& continuation_vector = @@ -1017,8 +1009,7 @@ auto Interpreter::StepStmt() -> Transition { } while (paused.back()->continuation == std::nullopt); // Update the continuation with the paused stack. heap.Write(*paused.back()->continuation, - global_arena->New(paused), - stmt->SourceLoc()); + arena->New(paused), stmt->SourceLoc()); return ManualTransition{}; } } @@ -1096,11 +1087,13 @@ class Interpreter::DoTransition { values.Set(name, value); params.push_back(name); } - auto scopes = Stack>(global_arena->New(values, params)); + auto scopes = + Stack>(interpreter->arena->New(values, params)); CHECK(call.function->Body()) << "Calling a function that's missing a body"; auto todo = Stack>( - global_arena->New(*call.function->Body())); - auto frame = global_arena->New(call.function->Name(), scopes, todo); + interpreter->arena->New(*call.function->Body())); + auto frame = + interpreter->arena->New(call.function->Name(), scopes, todo); interpreter->stack.Push(frame); } @@ -1149,13 +1142,12 @@ auto Interpreter::InterpProgram(const std::vector>& fs) SourceLocation loc("", 0); - Ptr arg = global_arena->New(loc); - Ptr call_main = global_arena->New( - loc, global_arena->New(loc, "main"), arg); - auto todo = - Stack>(global_arena->New(call_main)); - auto scopes = Stack>(global_arena->New(globals)); - stack = Stack>(global_arena->New("top", scopes, todo)); + Ptr arg = arena->New(loc); + Ptr call_main = arena->New( + loc, arena->New(loc, "main"), arg); + auto todo = Stack>(arena->New(call_main)); + auto scopes = Stack>(arena->New(globals)); + stack = Stack>(arena->New("top", scopes, todo)); if (tracing_output) { llvm::outs() << "********** calling main function **********\n"; @@ -1176,10 +1168,9 @@ auto Interpreter::InterpExp(Env values, Ptr e) CHECK(program_value == std::nullopt); auto program_value_guard = llvm::make_scope_exit([&] { program_value = std::nullopt; }); - auto todo = Stack>(global_arena->New(e)); - auto scopes = Stack>(global_arena->New(values)); - stack = - Stack>(global_arena->New("InterpExp", scopes, todo)); + auto todo = Stack>(arena->New(e)); + auto scopes = Stack>(arena->New(values)); + stack = Stack>(arena->New("InterpExp", scopes, todo)); while (stack.Count() > 1 || !stack.Top()->todo.IsEmpty()) { Step(); @@ -1193,10 +1184,9 @@ auto Interpreter::InterpPattern(Env values, Ptr p) CHECK(program_value == std::nullopt); auto program_value_guard = llvm::make_scope_exit([&] { program_value = std::nullopt; }); - auto todo = Stack>(global_arena->New(p)); - auto scopes = Stack>(global_arena->New(values)); - stack = Stack>( - global_arena->New("InterpPattern", scopes, todo)); + auto todo = Stack>(arena->New(p)); + auto scopes = Stack>(arena->New(values)); + stack = Stack>(arena->New("InterpPattern", scopes, todo)); while (stack.Count() > 1 || !stack.Top()->todo.IsEmpty()) { Step(); diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h index 6a2aba777abc..d824d97a3096 100644 --- a/executable_semantics/interpreter/interpreter.h +++ b/executable_semantics/interpreter/interpreter.h @@ -24,6 +24,9 @@ using Env = Dictionary; class Interpreter { public: + explicit Interpreter(Ptr arena) + : arena(arena), globals(arena), heap(arena) {} + // Interpret the whole program. auto InterpProgram(const std::vector>& fs) -> int; @@ -130,11 +133,19 @@ class Interpreter { void DeallocateScope(Ptr scope); void DeallocateLocals(Ptr frame); + auto CreateTuple(Ptr act, Ptr exp) + -> Ptr; + + auto EvalPrim(Operator op, const std::vector>& args, + SourceLocation loc) -> Ptr; + void PatternAssignment(Ptr pat, Ptr val, SourceLocation loc); void PrintState(llvm::raw_ostream& out); + Ptr arena; + // Globally-defined entities, such as functions, structs, or choices. Env globals; diff --git a/executable_semantics/interpreter/type_checker.cpp b/executable_semantics/interpreter/type_checker.cpp index d8903b1f7386..529c6b8a3b18 100644 --- a/executable_semantics/interpreter/type_checker.cpp +++ b/executable_semantics/interpreter/type_checker.cpp @@ -50,21 +50,20 @@ static void ExpectPointerType(SourceLocation loc, const std::string& context, } } -// Reify type to type expression. -static auto ReifyType(Ptr t, SourceLocation loc) +auto TypeChecker::ReifyType(Ptr t, SourceLocation loc) -> Ptr { switch (t->Tag()) { case Value::Kind::IntType: - return global_arena->New(loc); + return arena->New(loc); case Value::Kind::BoolType: - return global_arena->New(loc); + return arena->New(loc); case Value::Kind::TypeType: - return global_arena->New(loc); + return arena->New(loc); case Value::Kind::ContinuationType: - return global_arena->New(loc); + return arena->New(loc); case Value::Kind::FunctionType: { const auto& fn_type = cast(*t); - return global_arena->New( + return arena->New( loc, ReifyType(fn_type.Param(), loc), ReifyType(fn_type.Ret(), loc), /*is_omitted_return_type=*/false); } @@ -74,24 +73,22 @@ static auto ReifyType(Ptr t, SourceLocation loc) args.push_back( FieldInitializer(field.name, ReifyType(field.value, loc))); } - return global_arena->New(loc, args); + return arena->New(loc, args); } case Value::Kind::ClassType: - return global_arena->New( - loc, cast(*t).Name()); + return arena->New(loc, cast(*t).Name()); case Value::Kind::ChoiceType: - return global_arena->New( - loc, cast(*t).Name()); + return arena->New(loc, cast(*t).Name()); case Value::Kind::PointerType: - return global_arena->New( + return arena->New( loc, Operator::Ptr, std::vector>( {ReifyType(cast(*t).Type(), loc)})); case Value::Kind::VariableType: - return global_arena->New( - loc, cast(*t).Name()); + return arena->New(loc, + cast(*t).Name()); case Value::Kind::StringType: - return global_arena->New(loc); + return arena->New(loc); case Value::Kind::AlternativeConstructorValue: case Value::Kind::AlternativeValue: case Value::Kind::AutoType: @@ -195,7 +192,7 @@ static auto ArgumentDeduction(SourceLocation loc, TypeEnv deduced, } } -static auto Substitute(TypeEnv dict, Ptr type) +auto TypeChecker::Substitute(TypeEnv dict, Ptr type) -> Ptr { switch (type->Tag()) { case Value::Kind::VariableType: { @@ -213,17 +210,17 @@ static auto Substitute(TypeEnv dict, Ptr type) auto t = Substitute(dict, elt.value); elts.push_back({.name = elt.name, .value = t}); } - return global_arena->New(elts); + return arena->New(elts); } case Value::Kind::FunctionType: { const auto& fn_type = cast(*type); auto param = Substitute(dict, fn_type.Param()); auto ret = Substitute(dict, fn_type.Ret()); - return global_arena->New(std::vector(), - param, ret); + return arena->New(std::vector(), param, + ret); } case Value::Kind::PointerType: { - return global_arena->New( + return arena->New( Substitute(dict, cast(*type).Type())); } case Value::Kind::AutoType: @@ -276,9 +273,9 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, FATAL_COMPILATION_ERROR(e->SourceLoc()) << "field " << f << " is not in the tuple " << *t; } - auto new_e = global_arena->New( + auto new_e = arena->New( e->SourceLoc(), res.exp, - global_arena->New(e->SourceLoc(), i)); + arena->New(e->SourceLoc(), i)); return TCExpression(new_e, *field_t, res.types); } default: @@ -295,8 +292,8 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, new_args.push_back(FieldInitializer(arg.name, arg_res.exp)); arg_types.push_back({.name = arg.name, .value = arg_res.type}); } - auto tuple_e = global_arena->New(e->SourceLoc(), new_args); - auto tuple_t = global_arena->New(std::move(arg_types)); + auto tuple_e = arena->New(e->SourceLoc(), new_args); + auto tuple_t = arena->New(std::move(arg_types)); return TCExpression(tuple_e, tuple_t, new_types); } case Expression::Kind::FieldAccessExpression: { @@ -309,18 +306,16 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, // Search for a field for (auto& field : t_class.Fields()) { if (access.Field() == field.first) { - Ptr new_e = - global_arena->New( - e->SourceLoc(), res.exp, access.Field()); + Ptr new_e = arena->New( + e->SourceLoc(), res.exp, access.Field()); return TCExpression(new_e, field.second, res.types); } } // Search for a method for (auto& method : t_class.Methods()) { if (access.Field() == method.first) { - Ptr new_e = - global_arena->New( - e->SourceLoc(), res.exp, access.Field()); + Ptr new_e = arena->New( + e->SourceLoc(), res.exp, access.Field()); return TCExpression(new_e, method.second, res.types); } } @@ -332,7 +327,7 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, const auto& tup = cast(*t); for (const TupleElement& field : tup.Elements()) { if (access.Field() == field.name) { - auto new_e = global_arena->New( + auto new_e = arena->New( e->SourceLoc(), res.exp, access.Field()); return TCExpression(new_e, field.value, res.types); } @@ -345,10 +340,9 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, const auto& choice = cast(*t); for (const auto& vt : choice.Alternatives()) { if (access.Field() == vt.first) { - Ptr new_e = - global_arena->New( - e->SourceLoc(), res.exp, access.Field()); - auto fun_ty = global_arena->New( + Ptr new_e = arena->New( + e->SourceLoc(), res.exp, access.Field()); + auto fun_ty = arena->New( std::vector(), vt.second, t); return TCExpression(new_e, fun_ty, res.types); } @@ -374,9 +368,9 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, } } case Expression::Kind::IntLiteral: - return TCExpression(e, global_arena->New(), types); + return TCExpression(e, arena->New(), types); case Expression::Kind::BoolLiteral: - return TCExpression(e, global_arena->New(), types); + return TCExpression(e, arena->New(), types); case Expression::Kind::PrimitiveOperatorExpression: { const auto& op = cast(*e); std::vector> es; @@ -388,56 +382,51 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, es.push_back(res.exp); ts.push_back(res.type); } - auto new_e = global_arena->New( - e->SourceLoc(), op.Op(), es); + auto new_e = + arena->New(e->SourceLoc(), op.Op(), es); switch (op.Op()) { case Operator::Neg: - ExpectType(e->SourceLoc(), "negation", global_arena->New(), - ts[0]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "negation", arena->New(), ts[0]); + return TCExpression(new_e, arena->New(), new_types); case Operator::Add: - ExpectType(e->SourceLoc(), "addition(1)", - global_arena->New(), ts[0]); - ExpectType(e->SourceLoc(), "addition(2)", - global_arena->New(), ts[1]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "addition(1)", arena->New(), + ts[0]); + ExpectType(e->SourceLoc(), "addition(2)", arena->New(), + ts[1]); + return TCExpression(new_e, arena->New(), new_types); case Operator::Sub: - ExpectType(e->SourceLoc(), "subtraction(1)", - global_arena->New(), ts[0]); - ExpectType(e->SourceLoc(), "subtraction(2)", - global_arena->New(), ts[1]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "subtraction(1)", arena->New(), + ts[0]); + ExpectType(e->SourceLoc(), "subtraction(2)", arena->New(), + ts[1]); + return TCExpression(new_e, arena->New(), new_types); case Operator::Mul: - ExpectType(e->SourceLoc(), "multiplication(1)", - global_arena->New(), ts[0]); - ExpectType(e->SourceLoc(), "multiplication(2)", - global_arena->New(), ts[1]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "multiplication(1)", arena->New(), + ts[0]); + ExpectType(e->SourceLoc(), "multiplication(2)", arena->New(), + ts[1]); + return TCExpression(new_e, arena->New(), new_types); case Operator::And: - ExpectType(e->SourceLoc(), "&&(1)", global_arena->New(), - ts[0]); - ExpectType(e->SourceLoc(), "&&(2)", global_arena->New(), - ts[1]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "&&(1)", arena->New(), ts[0]); + ExpectType(e->SourceLoc(), "&&(2)", arena->New(), ts[1]); + return TCExpression(new_e, arena->New(), new_types); case Operator::Or: - ExpectType(e->SourceLoc(), "||(1)", global_arena->New(), - ts[0]); - ExpectType(e->SourceLoc(), "||(2)", global_arena->New(), - ts[1]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "||(1)", arena->New(), ts[0]); + ExpectType(e->SourceLoc(), "||(2)", arena->New(), ts[1]); + return TCExpression(new_e, arena->New(), new_types); case Operator::Not: - ExpectType(e->SourceLoc(), "!", global_arena->New(), ts[0]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "!", arena->New(), ts[0]); + return TCExpression(new_e, arena->New(), new_types); case Operator::Eq: ExpectType(e->SourceLoc(), "==", ts[0], ts[1]); - return TCExpression(new_e, global_arena->New(), new_types); + return TCExpression(new_e, arena->New(), new_types); case Operator::Deref: ExpectPointerType(e->SourceLoc(), "*", ts[0]); return TCExpression(new_e, cast(*ts[0]).Type(), new_types); case Operator::Ptr: - ExpectType(e->SourceLoc(), "*", global_arena->New(), ts[0]); - return TCExpression(new_e, global_arena->New(), new_types); + ExpectType(e->SourceLoc(), "*", arena->New(), ts[0]); + return TCExpression(new_e, arena->New(), new_types); } break; } @@ -451,8 +440,8 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, auto parameter_type = fun_t.Param(); auto return_type = fun_t.Ret(); if (!fun_t.Deduced().empty()) { - auto deduced_args = ArgumentDeduction(e->SourceLoc(), TypeEnv(), - parameter_type, arg_res.type); + auto deduced_args = ArgumentDeduction( + e->SourceLoc(), TypeEnv(arena), parameter_type, arg_res.type); for (auto& deduced_param : fun_t.Deduced()) { // TODO: change the following to a CHECK once the real checking // has been added to the type checking of function signatures. @@ -467,8 +456,8 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, } else { ExpectType(e->SourceLoc(), "call", parameter_type, arg_res.type); } - auto new_e = global_arena->New( - e->SourceLoc(), fun_res.exp, arg_res.exp); + auto new_e = arena->New(e->SourceLoc(), fun_res.exp, + arg_res.exp); return TCExpression(new_e, return_type, arg_res.types); } default: { @@ -483,14 +472,14 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, const auto& fn = cast(*e); auto pt = interpreter.InterpExp(values, fn.Parameter()); auto rt = interpreter.InterpExp(values, fn.ReturnType()); - auto new_e = global_arena->New( + auto new_e = arena->New( e->SourceLoc(), ReifyType(pt, e->SourceLoc()), ReifyType(rt, e->SourceLoc()), /*is_omitted_return_type=*/false); - return TCExpression(new_e, global_arena->New(), types); + return TCExpression(new_e, arena->New(), types); } case Expression::Kind::StringLiteral: - return TCExpression(e, global_arena->New(), types); + return TCExpression(e, arena->New(), types); case Expression::Kind::IntrinsicExpression: switch (cast(*e).Intrinsic()) { case IntrinsicExpression::IntrinsicKind::Print: @@ -501,7 +490,7 @@ auto TypeChecker::TypeCheckExp(Ptr e, TypeEnv types, case Expression::Kind::StringTypeLiteral: case Expression::Kind::TypeTypeLiteral: case Expression::Kind::ContinuationTypeLiteral: - return TCExpression(e, global_arena->New(), types); + return TCExpression(e, arena->New(), types); } } @@ -522,8 +511,7 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, } switch (p->Tag()) { case Pattern::Kind::AutoPattern: { - return { - .pattern = p, .type = global_arena->New(), .types = types}; + return {.pattern = p, .type = arena->New(), .types = types}; } case Pattern::Kind::BindingPattern: { const auto& binding = cast(*p); @@ -543,10 +531,9 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, << "Name bindings within type patterns are unsupported"; type = *expected; } - auto new_p = global_arena->New( + auto new_p = arena->New( binding.SourceLoc(), binding.Name(), - global_arena->New( - ReifyType(type, binding.SourceLoc()))); + arena->New(ReifyType(type, binding.SourceLoc()))); if (binding.Name().has_value()) { types.Set(*binding.Name(), type); } @@ -585,9 +572,8 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, TuplePattern::Field(field.name, field_result.pattern)); field_types.push_back({.name = field.name, .value = field_result.type}); } - auto new_tuple = - global_arena->New(tuple.SourceLoc(), new_fields); - auto tuple_t = global_arena->New(std::move(field_types)); + auto new_tuple = arena->New(tuple.SourceLoc(), new_fields); + auto tuple_t = arena->New(std::move(field_types)); return {.pattern = new_tuple, .type = tuple_t, .types = new_types}; } case Pattern::Kind::AlternativePattern: { @@ -616,7 +602,7 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, // (multiple TODOs) auto arguments = Ptr( cast(arg_results.pattern.Get())); - return {.pattern = global_arena->New( + return {.pattern = arena->New( alternative.SourceLoc(), ReifyType(choice_type, alternative.SourceLoc()), alternative.AlternativeName(), arguments), @@ -626,7 +612,7 @@ auto TypeChecker::TypeCheckPattern(Ptr p, TypeEnv types, case Pattern::Kind::ExpressionPattern: { TCExpression result = TypeCheckExp(cast(*p).Expression(), types, values); - return {.pattern = global_arena->New(result.exp), + return {.pattern = arena->New(result.exp), .type = result.type, .types = result.types}; } @@ -660,19 +646,18 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, clause.second, types, values, ret_type, is_omitted_ret_type)); } - auto new_s = - global_arena->New(s->SourceLoc(), res.exp, new_clauses); + auto new_s = arena->New(s->SourceLoc(), res.exp, new_clauses); return TCStatement(new_s, types); } case Statement::Kind::While: { const auto& while_stmt = cast(*s); auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values); - ExpectType(s->SourceLoc(), "condition of `while`", - global_arena->New(), cnd_res.type); + ExpectType(s->SourceLoc(), "condition of `while`", arena->New(), + cnd_res.type); auto body_res = TypeCheckStmt(while_stmt.Body(), types, values, ret_type, is_omitted_ret_type); auto new_s = - global_arena->New(s->SourceLoc(), cnd_res.exp, body_res.stmt); + arena->New(s->SourceLoc(), cnd_res.exp, body_res.stmt); return TCStatement(new_s, types); } case Statement::Kind::Break: @@ -683,8 +668,8 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, if (block.Stmt()) { auto stmt_res = TypeCheckStmt(*block.Stmt(), types, values, ret_type, is_omitted_ret_type); - return TCStatement( - global_arena->New(s->SourceLoc(), stmt_res.stmt), types); + return TCStatement(arena->New(s->SourceLoc(), stmt_res.stmt), + types); } else { return TCStatement(s, types); } @@ -694,8 +679,8 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, auto res = TypeCheckExp(var.Init(), types, values); Ptr rhs_ty = res.type; auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty); - auto new_s = global_arena->New(s->SourceLoc(), - var.Pat(), res.exp); + auto new_s = + arena->New(s->SourceLoc(), var.Pat(), res.exp); return TCStatement(new_s, lhs_res.types); } case Statement::Kind::Sequence: { @@ -711,7 +696,7 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, checked_types = next_res.types; } return TCStatement( - global_arena->New(s->SourceLoc(), stmt_res.stmt, next_stmt), + arena->New(s->SourceLoc(), stmt_res.stmt, next_stmt), checked_types); } case Statement::Kind::Assign: { @@ -721,22 +706,20 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, auto lhs_res = TypeCheckExp(assign.Lhs(), types, values); auto lhs_t = lhs_res.type; ExpectType(s->SourceLoc(), "assign", lhs_t, rhs_t); - auto new_s = - global_arena->New(s->SourceLoc(), lhs_res.exp, rhs_res.exp); + auto new_s = arena->New(s->SourceLoc(), lhs_res.exp, rhs_res.exp); return TCStatement(new_s, lhs_res.types); } case Statement::Kind::ExpressionStatement: { auto res = TypeCheckExp(cast(*s).Exp(), types, values); - auto new_s = - global_arena->New(s->SourceLoc(), res.exp); + auto new_s = arena->New(s->SourceLoc(), res.exp); return TCStatement(new_s, types); } case Statement::Kind::If: { const auto& if_stmt = cast(*s); auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values); - ExpectType(s->SourceLoc(), "condition of `if`", - global_arena->New(), cnd_res.type); + ExpectType(s->SourceLoc(), "condition of `if`", arena->New(), + cnd_res.type); auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type, is_omitted_ret_type); std::optional> else_stmt; @@ -745,8 +728,8 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, ret_type, is_omitted_ret_type); else_stmt = else_res.stmt; } - auto new_s = global_arena->New(s->SourceLoc(), cnd_res.exp, - then_res.stmt, else_stmt); + auto new_s = + arena->New(s->SourceLoc(), cnd_res.exp, then_res.stmt, else_stmt); return TCStatement(new_s, types); } case Statement::Kind::Return: { @@ -765,27 +748,25 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, << *s << " should" << (is_omitted_ret_type ? " not" : "") << " provide a return value, to match the function's signature."; } - return TCStatement(global_arena->New(s->SourceLoc(), res.exp, - ret.IsOmittedExp()), - types); + return TCStatement( + arena->New(s->SourceLoc(), res.exp, ret.IsOmittedExp()), + types); } case Statement::Kind::Continuation: { const auto& cont = cast(*s); TCStatement body_result = TypeCheckStmt(cont.Body(), types, values, ret_type, is_omitted_ret_type); - auto new_continuation = global_arena->New( + auto new_continuation = arena->New( s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt); - types.Set(cont.ContinuationVariable(), - global_arena->New()); + types.Set(cont.ContinuationVariable(), arena->New()); return TCStatement(new_continuation, types); } case Statement::Kind::Run: { TCExpression argument_result = TypeCheckExp(cast(*s).Argument(), types, values); ExpectType(s->SourceLoc(), "argument of `run`", - global_arena->New(), argument_result.type); - auto new_run = - global_arena->New(s->SourceLoc(), argument_result.exp); + arena->New(), argument_result.type); + auto new_run = arena->New(s->SourceLoc(), argument_result.exp); return TCStatement(new_run, types); } case Statement::Kind::Await: { @@ -795,12 +776,12 @@ auto TypeChecker::TypeCheckStmt(Ptr s, TypeEnv types, } // switch } -static auto CheckOrEnsureReturn(std::optional> opt_stmt, - bool omitted_ret_type, SourceLocation loc) - -> Ptr { +auto TypeChecker::CheckOrEnsureReturn( + std::optional> opt_stmt, bool omitted_ret_type, + SourceLocation loc) -> Ptr { if (!opt_stmt) { if (omitted_ret_type) { - return global_arena->New(loc); + return arena->New(arena, loc); } else { FATAL_COMPILATION_ERROR(loc) << "control-flow reaches end of function that provides a `->` return " @@ -818,17 +799,16 @@ static auto CheckOrEnsureReturn(std::optional> opt_stmt, stmt->SourceLoc()); new_clauses.push_back(std::make_pair(clause.first, s)); } - return global_arena->New(stmt->SourceLoc(), match.Exp(), - new_clauses); + return arena->New(stmt->SourceLoc(), match.Exp(), new_clauses); } case Statement::Kind::Block: - return global_arena->New( + return arena->New( stmt->SourceLoc(), CheckOrEnsureReturn(cast(*stmt).Stmt(), omitted_ret_type, stmt->SourceLoc())); case Statement::Kind::If: { const auto& if_stmt = cast(*stmt); - return global_arena->New( + return arena->New( stmt->SourceLoc(), if_stmt.Cond(), CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type, stmt->SourceLoc()), @@ -840,7 +820,7 @@ static auto CheckOrEnsureReturn(std::optional> opt_stmt, case Statement::Kind::Sequence: { const auto& seq = cast(*stmt); if (seq.Next()) { - return global_arena->New( + return arena->New( stmt->SourceLoc(), seq.Stmt(), CheckOrEnsureReturn(seq.Next(), omitted_ret_type, stmt->SourceLoc())); @@ -860,8 +840,8 @@ static auto CheckOrEnsureReturn(std::optional> opt_stmt, case Statement::Kind::Continue: case Statement::Kind::VariableDefinition: if (omitted_ret_type) { - return global_arena->New(stmt->SourceLoc(), stmt, - global_arena->New(loc)); + return arena->New(stmt->SourceLoc(), stmt, + arena->New(arena, loc)); } else { FATAL_COMPILATION_ERROR(stmt->SourceLoc()) << "control-flow reaches end of function that provides a `->` " @@ -879,7 +859,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, // Bring the deduced parameters into scope for (const auto& deduced : f->deduced_parameters) { // auto t = interpreter.InterpExp(values, deduced.type); - types.Set(deduced.name, global_arena->New(deduced.name)); + types.Set(deduced.name, arena->New(deduced.name)); Address a = interpreter.AllocateValue(*types.Get(deduced.name)); values.Set(deduced.name, a); } @@ -890,7 +870,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, auto return_type = interpreter.InterpPattern(values, f->return_type); if (f->name == "main") { ExpectType(f->source_location, "return type of `main`", - global_arena->New(), return_type); + arena->New(), return_type); // TODO: Check that main doesn't have any parameters. } std::optional> body_stmt; @@ -901,10 +881,9 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types, } auto body = CheckOrEnsureReturn(body_stmt, f->is_omitted_return_type, f->source_location); - return global_arena->New( + return arena->New( f->source_location, f->name, f->deduced_parameters, f->param_pattern, - global_arena->New( - ReifyType(return_type, f->source_location)), + arena->New(ReifyType(return_type, f->source_location)), /*is_omitted_return_type=*/false, body); } @@ -914,7 +893,7 @@ auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values, // Bring the deduced parameters into scope for (const auto& deduced : fun_def->deduced_parameters) { // auto t = interpreter.InterpExp(values, deduced.type); - types.Set(deduced.name, global_arena->New(deduced.name)); + types.Set(deduced.name, arena->New(deduced.name)); Address a = interpreter.AllocateValue(*types.Get(deduced.name)); values.Set(deduced.name, a); } @@ -927,8 +906,8 @@ auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values, auto f = TypeCheckFunDef(fun_def, types, values); ret = interpreter.InterpPattern(values, f->return_type); } - return global_arena->New(fun_def->deduced_parameters, - param_res.type, ret); + return arena->New(fun_def->deduced_parameters, param_res.type, + ret); } auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, @@ -955,8 +934,7 @@ auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/, } } } - return global_arena->New(sd->name, std::move(fields), - std::move(methods)); + return arena->New(sd->name, std::move(fields), std::move(methods)); } static auto GetName(const Declaration& d) -> const std::string& { @@ -984,7 +962,7 @@ auto TypeChecker::MakeTypeChecked(const Ptr d, -> Ptr { switch (d->Tag()) { case Declaration::Kind::FunctionDeclaration: - return global_arena->New(TypeCheckFunDef( + return arena->New(TypeCheckFunDef( &cast(*d).Definition(), types, values)); case Declaration::Kind::ClassDeclaration: { @@ -999,8 +977,8 @@ auto TypeChecker::MakeTypeChecked(const Ptr d, break; } } - return global_arena->New(class_def.loc, class_def.name, - std::move(fields)); + return arena->New(class_def.loc, class_def.name, + std::move(fields)); } case Declaration::Kind::ChoiceDeclaration: @@ -1051,9 +1029,9 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) { cast(*st).Fields()) { field_types.push_back({.name = field_name, .value = field_value}); } - auto fun_ty = global_arena->New( + auto fun_ty = arena->New( std::vector(), - global_arena->New(std::move(field_types)), st); + arena->New(std::move(field_types)), st); tops->types.Set(class_def.name, fun_ty); break; } @@ -1065,7 +1043,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) { auto t = interpreter.InterpExp(tops->values, signature); alts.push_back(std::make_pair(name, t)); } - auto ct = global_arena->New(choice.Name(), std::move(alts)); + auto ct = arena->New(choice.Name(), std::move(alts)); Address a = interpreter.AllocateValue(ct); tops->values.Set(choice.Name(), a); // Is this obsolete? tops->types.Set(choice.Name(), ct); @@ -1088,7 +1066,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) { auto TypeChecker::TopLevel(const std::vector>& fs) -> TypeCheckContext { - TypeCheckContext tops; + TypeCheckContext tops(arena); bool found_main = false; for (auto const& d : fs) { diff --git a/executable_semantics/interpreter/type_checker.h b/executable_semantics/interpreter/type_checker.h index 186d682d5f27..13cc86804815 100644 --- a/executable_semantics/interpreter/type_checker.h +++ b/executable_semantics/interpreter/type_checker.h @@ -20,7 +20,11 @@ using TypeEnv = Dictionary>; class TypeChecker { public: + explicit TypeChecker(Ptr arena) : arena(arena), interpreter(arena) {} + struct TypeCheckContext { + TypeCheckContext(Ptr arena) : types(arena), values(arena) {} + // Symbol table mapping names of runtime entities to their type. TypeEnv types; // Symbol table mapping names of compile time entities to their value. @@ -104,6 +108,17 @@ class TypeChecker { void TopLevel(const Declaration& d, TypeCheckContext* tops); + auto CheckOrEnsureReturn(std::optional> opt_stmt, + bool omitted_ret_type, SourceLocation loc) + -> Ptr; + + // Reify type to type expression. + auto ReifyType(Ptr t, SourceLocation loc) + -> Ptr; + + auto Substitute(TypeEnv dict, Ptr type) -> Ptr; + + Ptr arena; Interpreter interpreter; }; diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index e5d34b8a5a59..4ef89da59550 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -56,8 +56,8 @@ auto TupleValue::FindField(const std::string& name) const namespace { -auto GetMember(Ptr v, const std::string& f, SourceLocation loc) - -> Ptr { +auto GetMember(Ptr arena, Ptr v, const std::string& f, + SourceLocation loc) -> Ptr { switch (v->Tag()) { case Value::Kind::StructValue: { std::optional> field = @@ -79,7 +79,7 @@ auto GetMember(Ptr v, const std::string& f, SourceLocation loc) if (!FindInVarValues(f, choice.Alternatives())) { FATAL_RUNTIME_ERROR(loc) << "alternative " << f << " not in " << *v; } - return global_arena->New(f, choice.Name()); + return arena->New(f, choice.Name()); } default: FATAL() << "field access not allowed for value " << *v; @@ -88,18 +88,18 @@ auto GetMember(Ptr v, const std::string& f, SourceLocation loc) } // namespace -auto Value::GetField(const FieldPath& path, SourceLocation loc) const - -> Ptr { +auto Value::GetField(Ptr arena, const FieldPath& path, + SourceLocation loc) const -> Ptr { Ptr value(this); for (const std::string& field : path.components) { - value = GetMember(value, field, loc); + value = GetMember(arena, value, field, loc); } return value; } namespace { -auto SetFieldImpl(Ptr value, +auto SetFieldImpl(Ptr arena, Ptr value, std::vector::const_iterator path_begin, std::vector::const_iterator path_end, Ptr field_value, SourceLocation loc) @@ -109,7 +109,7 @@ auto SetFieldImpl(Ptr value, } switch (value->Tag()) { case Value::Kind::StructValue: { - return SetFieldImpl(cast(*value).Inits(), path_begin, + return SetFieldImpl(arena, cast(*value).Inits(), path_begin, path_end, field_value, loc); } case Value::Kind::TupleValue: { @@ -122,9 +122,9 @@ auto SetFieldImpl(Ptr value, FATAL_RUNTIME_ERROR(loc) << "field " << *path_begin << " not in " << *value; } - it->value = - SetFieldImpl(it->value, path_begin + 1, path_end, field_value, loc); - return global_arena->New(elements); + it->value = SetFieldImpl(arena, it->value, path_begin + 1, path_end, + field_value, loc); + return arena->New(elements); } default: FATAL() << "field access not allowed for value " << *value; @@ -133,9 +133,10 @@ auto SetFieldImpl(Ptr value, } // namespace -auto Value::SetField(const FieldPath& path, Ptr field_value, - SourceLocation loc) const -> Ptr { - return SetFieldImpl(Ptr(this), path.components.begin(), +auto Value::SetField(Ptr arena, const FieldPath& path, + Ptr field_value, SourceLocation loc) const + -> Ptr { + return SetFieldImpl(arena, Ptr(this), path.components.begin(), path.components.end(), field_value, loc); } @@ -253,64 +254,64 @@ void Value::Print(llvm::raw_ostream& out) const { } } -auto CopyVal(Ptr val, SourceLocation loc) -> Ptr { +auto CopyVal(Ptr arena, Ptr val, SourceLocation loc) + -> Ptr { switch (val->Tag()) { case Value::Kind::TupleValue: { std::vector elements; for (const TupleElement& element : cast(*val).Elements()) { - elements.push_back( - {.name = element.name, .value = CopyVal(element.value, loc)}); + elements.push_back({.name = element.name, + .value = CopyVal(arena, element.value, loc)}); } - return global_arena->New(std::move(elements)); + return arena->New(std::move(elements)); } case Value::Kind::AlternativeValue: { const auto& alt = cast(*val); - Ptr arg = CopyVal(alt.Argument(), loc); - return global_arena->New(alt.AltName(), - alt.ChoiceName(), arg); + Ptr arg = CopyVal(arena, alt.Argument(), loc); + return arena->New(alt.AltName(), alt.ChoiceName(), arg); } case Value::Kind::StructValue: { const auto& s = cast(*val); - Ptr inits = CopyVal(s.Inits(), loc); - return global_arena->New(s.Type(), inits); + Ptr inits = CopyVal(arena, s.Inits(), loc); + return arena->New(s.Type(), inits); } case Value::Kind::IntValue: - return global_arena->New(cast(*val).Val()); + return arena->New(cast(*val).Val()); case Value::Kind::BoolValue: - return global_arena->New(cast(*val).Val()); + return arena->New(cast(*val).Val()); case Value::Kind::FunctionValue: { const auto& fn_value = cast(*val); - return global_arena->New(fn_value.Name(), fn_value.Param(), - fn_value.Body()); + return arena->New(fn_value.Name(), fn_value.Param(), + fn_value.Body()); } case Value::Kind::PointerValue: - return global_arena->New(cast(*val).Val()); + return arena->New(cast(*val).Val()); case Value::Kind::ContinuationValue: // Copying a continuation is "shallow". return val; case Value::Kind::FunctionType: { const auto& fn_type = cast(*val); - return global_arena->New(fn_type.Deduced(), - CopyVal(fn_type.Param(), loc), - CopyVal(fn_type.Ret(), loc)); + return arena->New(fn_type.Deduced(), + CopyVal(arena, fn_type.Param(), loc), + CopyVal(arena, fn_type.Ret(), loc)); } case Value::Kind::PointerType: - return global_arena->New( - CopyVal(cast(*val).Type(), loc)); + return arena->New( + CopyVal(arena, cast(*val).Type(), loc)); case Value::Kind::IntType: - return global_arena->New(); + return arena->New(); case Value::Kind::BoolType: - return global_arena->New(); + return arena->New(); case Value::Kind::TypeType: - return global_arena->New(); + return arena->New(); case Value::Kind::AutoType: - return global_arena->New(); + return arena->New(); case Value::Kind::ContinuationType: - return global_arena->New(); + return arena->New(); case Value::Kind::StringType: - return global_arena->New(); + return arena->New(); case Value::Kind::StringValue: - return global_arena->New(cast(*val).Val()); + return arena->New(cast(*val).Val()); case Value::Kind::VariableType: case Value::Kind::ClassType: case Value::Kind::ChoiceType: diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index 9cb3cf89d4a0..a092ef7aa3b9 100644 --- a/executable_semantics/interpreter/value.h +++ b/executable_semantics/interpreter/value.h @@ -68,13 +68,14 @@ class Value { // Returns the sub-Value specified by `path`, which must be a valid field // path for *this. - auto GetField(const FieldPath& path, SourceLocation loc) const - -> Ptr; + auto GetField(Ptr arena, const FieldPath& path, + SourceLocation loc) const -> Ptr; // Returns a copy of *this, but with the sub-Value specified by `path` // set to `field_value`. `path` must be a valid field path for *this. - auto SetField(const FieldPath& path, Ptr field_value, - SourceLocation loc) const -> Ptr; + auto SetField(Ptr arena, const FieldPath& path, + Ptr field_value, SourceLocation loc) const + -> Ptr; protected: // Constructs a Value. `tag` must be the enumerator corresponding to the @@ -474,7 +475,8 @@ class StringValue : public Value { std::string val; }; -auto CopyVal(Ptr val, SourceLocation loc) -> Ptr; +auto CopyVal(Ptr arena, Ptr val, SourceLocation loc) + -> Ptr; auto TypeEqual(Ptr t1, Ptr t2) -> bool; auto ValueEqual(Ptr v1, Ptr v2, SourceLocation loc) diff --git a/executable_semantics/main.cpp b/executable_semantics/main.cpp index aca0744f3a84..06eb2728418a 100644 --- a/executable_semantics/main.cpp +++ b/executable_semantics/main.cpp @@ -30,8 +30,9 @@ int main(int argc, char* argv[]) { Carbon::tracing_output = true; } + Carbon::Arena arena; std::variant ast_or_error = - Carbon::Parse(input_file_name); + Carbon::Parse(PtrTo(arena), input_file_name); if (auto* error = std::get_if(&ast_or_error)) { // Diagnostic already reported to std::cerr; this is just a return code. @@ -39,5 +40,5 @@ int main(int argc, char* argv[]) { } // Typecheck and run the parsed program. - Carbon::ExecProgram(std::get(ast_or_error)); + Carbon::ExecProgram(PtrTo(arena), std::get(ast_or_error)); } diff --git a/executable_semantics/syntax/parse.cpp b/executable_semantics/syntax/parse.cpp index 2e21c2788335..39f34f8fe71d 100644 --- a/executable_semantics/syntax/parse.cpp +++ b/executable_semantics/syntax/parse.cpp @@ -13,10 +13,7 @@ namespace Carbon { -// Returns an abstract representation of the program contained in the -// well-formed input file, or if the file was malformed, a description of the -// problem. -auto Parse(const std::string& input_file_name) +auto Parse(Ptr arena, const std::string& input_file_name) -> std::variant { FILE* input_file = fopen(input_file_name.c_str(), "r"); if (input_file == nullptr) { @@ -30,11 +27,11 @@ auto Parse(const std::string& input_file_name) yyset_in(input_file, scanner); // Prepare other parser arguments. - std::optional parsed_input = std::nullopt; - ParseAndLexContext context(input_file_name); + std::optional ast = std::nullopt; + ParseAndLexContext context(arena->New(input_file_name)); // Do the parse. - auto parser = Parser(parsed_input, scanner, context); + auto parser = Parser(arena, scanner, context, &ast); if (tracing_output) { parser.set_debug_level(1); } @@ -50,9 +47,9 @@ auto Parse(const std::string& input_file_name) } // Return parse results. - CHECK(parsed_input != std::nullopt) + CHECK(ast != std::nullopt) << "parser validated syntax yet didn't produce an AST."; - return *parsed_input; + return *ast; } } // namespace Carbon diff --git a/executable_semantics/syntax/parse.h b/executable_semantics/syntax/parse.h index 2d9ba6141093..cadef2b460f2 100644 --- a/executable_semantics/syntax/parse.h +++ b/executable_semantics/syntax/parse.h @@ -9,6 +9,7 @@ #include #include "executable_semantics/ast/ast.h" +#include "executable_semantics/common/arena.h" namespace Carbon { @@ -16,8 +17,8 @@ namespace Carbon { using SyntaxErrorCode = int; // Returns the AST representing the contents of the named file, or an error code -// if parsing fails. -auto Parse(const std::string& input_file_name) +// if parsing fails. Allocations go into the provided arena. +auto Parse(Ptr arena, const std::string& input_file_name) -> std::variant; } // namespace Carbon diff --git a/executable_semantics/syntax/parse_and_lex_context.h b/executable_semantics/syntax/parse_and_lex_context.h index 1d1d1fb75b8e..4e67e7127215 100644 --- a/executable_semantics/syntax/parse_and_lex_context.h +++ b/executable_semantics/syntax/parse_and_lex_context.h @@ -17,8 +17,8 @@ namespace Carbon { class ParseAndLexContext { public: // Creates an instance analyzing the given input file. - ParseAndLexContext(const std::string& input_file) - : input_file_name(global_arena->New(input_file)) {} + ParseAndLexContext(Ptr input_file_name) + : input_file_name(input_file_name) {} // Writes a syntax error diagnostic containing message to standard error. auto PrintDiagnostic(const std::string& message) -> void; @@ -40,8 +40,9 @@ class ParseAndLexContext { } // namespace Carbon // Gives flex the yylex prototype we want. -#define YY_DECL \ - Carbon::Parser::symbol_type yylex(yyscan_t yyscanner, \ +#define YY_DECL \ + Carbon::Parser::symbol_type yylex(Carbon::Ptr arena, \ + yyscan_t yyscanner, \ Carbon::ParseAndLexContext& context) // Declares yylex for the parser's sake. diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index ff2ed05238ce..1b4f5c409b4a 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -37,13 +37,14 @@ // Parameters to the parser are stored therein as protected data members, and // thus available to its methods. -// "out" parameter passed to the parser, where the AST is written. -%parse-param {std::optional& parsed_program} - // "inout" parameters passed to both the parser and the lexer. +%param {Ptr arena} %param {yyscan_t yyscanner} %param {ParseAndLexContext& context} +// "out" parameter passed to the parser, where the AST is written. +%parse-param {std::optional* ast} + // No shift-reduce conflicts are expected. %expect 0 @@ -231,10 +232,10 @@ %% input: package_directive import_directives declaration_list { - parsed_program = AST({.package = $1.first, - .is_api = $1.second, - .imports = std::move($2), - .declarations = std::move($3)}); + *ast = AST({.package = $1.first, + .is_api = $1.second, + .imports = std::move($2), + .declarations = std::move($3)}); } ; package_directive: @@ -268,127 +269,124 @@ api_or_impl: ; expression: identifier - { $$ = global_arena->New(context.SourceLoc(), $1); } + { $$ = arena->New(context.SourceLoc(), $1); } | expression designator - { - $$ = - global_arena->New(context.SourceLoc(), $1, $2); - } + { $$ = arena->New(context.SourceLoc(), $1, $2); } | expression LEFT_SQUARE_BRACKET expression RIGHT_SQUARE_BRACKET - { $$ = global_arena->New(context.SourceLoc(), $1, $3); } + { $$ = arena->New(context.SourceLoc(), $1, $3); } | integer_literal - { $$ = global_arena->New(context.SourceLoc(), $1); } + { $$ = arena->New(context.SourceLoc(), $1); } | string_literal - { $$ = global_arena->New(context.SourceLoc(), $1); } + { $$ = arena->New(context.SourceLoc(), $1); } | TRUE - { $$ = global_arena->New(context.SourceLoc(), true); } + { $$ = arena->New(context.SourceLoc(), true); } | FALSE - { $$ = global_arena->New(context.SourceLoc(), false); } + { $$ = arena->New(context.SourceLoc(), false); } | sized_type_literal { int val; CHECK(llvm::to_integer(llvm::StringRef($1).substr(1), val)); CHECK($1[0] == 'i' && val == 32) << "Only i32 is supported for now: " << $1; - $$ = global_arena->New(context.SourceLoc()); + $$ = arena->New(context.SourceLoc()); } | STRING - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | BOOL - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | TYPE - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | CONTINUATION_TYPE - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | paren_expression { $$ = $1; } | expression EQUAL_EQUAL expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Eq, std::vector>({$1, $3})); } | expression PLUS expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Add, std::vector>({$1, $3})); } | expression MINUS expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Sub, std::vector>({$1, $3})); } | expression BINARY_STAR expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Mul, std::vector>({$1, $3})); } | expression AND expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::And, std::vector>({$1, $3})); } | expression OR expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Or, std::vector>({$1, $3})); } | NOT expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Not, std::vector>({$2})); } | MINUS expression %prec UNARY_MINUS { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Neg, std::vector>({$2})); } | PREFIX_STAR expression { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Deref, std::vector>({$2})); } | UNARY_STAR expression %prec PREFIX_STAR { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Deref, std::vector>({$2})); } | expression tuple - { $$ = global_arena->New(context.SourceLoc(), $1, $2); } + { $$ = arena->New(context.SourceLoc(), $1, $2); } | expression POSTFIX_STAR { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Ptr, std::vector>({$1})); } | expression UNARY_STAR { - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), Operator::Ptr, std::vector>({$1})); } | FNTY tuple return_type { auto [return_exp, is_omitted_exp] = $3.Release(); - $$ = global_arena->New(context.SourceLoc(), $2, - return_exp, is_omitted_exp); + $$ = arena->New(context.SourceLoc(), $2, return_exp, + is_omitted_exp); } ; designator: PERIOD identifier { $$ = $2; } ; paren_expression: paren_expression_base - { $$ = ExpressionFromParenContents(context.SourceLoc(), $1); } + { $$ = ExpressionFromParenContents(arena, context.SourceLoc(), $1); } ; tuple: paren_expression_base - { $$ = TupleExpressionFromParenContents(context.SourceLoc(), $1); } + { $$ = TupleExpressionFromParenContents(arena, context.SourceLoc(), $1); } ; paren_expression_element: expression @@ -427,24 +425,24 @@ pattern: non_expression_pattern { $$ = $1; } | expression - { $$ = global_arena->New($1); } + { $$ = arena->New($1); } ; non_expression_pattern: AUTO - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | binding_lhs COLON pattern - { $$ = global_arena->New(context.SourceLoc(), $1, $3); } + { $$ = arena->New(context.SourceLoc(), $1, $3); } | paren_pattern { $$ = $1; } | expression tuple_pattern - { $$ = global_arena->New(context.SourceLoc(), $1, $2); } + { $$ = arena->New(context.SourceLoc(), $1, $2); } ; binding_lhs: identifier { $$ = $1; } | UNDERSCORE { $$ = std::nullopt; } ; paren_pattern: paren_pattern_base - { $$ = PatternFromParenContents(context.SourceLoc(), $1); } + { $$ = PatternFromParenContents(arena, context.SourceLoc(), $1); } ; paren_pattern_base: LEFT_PARENTHESIS paren_pattern_contents RIGHT_PARENTHESIS @@ -465,16 +463,15 @@ paren_pattern_contents: { $$ = {.elements = {$1}, .has_trailing_comma = false}; } | paren_expression_contents COMMA paren_pattern_element { - $$ = ParenExpressionToParenPattern($1); + $$ = ParenExpressionToParenPattern(arena, $1); $$.elements.push_back($3); } | paren_pattern_contents COMMA paren_expression_element { $$ = $1; auto el = $3.Release(); - $$.elements.push_back( - {.name = el.name, - .term = global_arena->New(el.term)}); + $$.elements.push_back({.name = el.name, + .term = arena->New(el.term)}); } | paren_pattern_contents COMMA paren_pattern_element { @@ -489,7 +486,7 @@ paren_pattern_element: { $$ = {.name = $1, .term = $3}; } ; tuple_pattern: paren_pattern_base - { $$ = TuplePatternFromParenContents(context.SourceLoc(), $1); } + { $$ = TuplePatternFromParenContents(arena, context.SourceLoc(), $1); } ; // Unlike most `pattern` nonterminals, this one overlaps with `expression`, // so it should be used only when prior context (such as an introducer) @@ -497,8 +494,8 @@ tuple_pattern: paren_pattern_base maybe_empty_tuple_pattern: LEFT_PARENTHESIS RIGHT_PARENTHESIS { - $$ = global_arena->New(context.SourceLoc(), - std::vector()); + $$ = arena->New(context.SourceLoc(), + std::vector()); } | tuple_pattern { $$ = $1; } @@ -508,9 +505,9 @@ clause: { $$ = std::pair, Ptr>($2, $4); } | DEFAULT DOUBLE_ARROW statement { - auto vp = global_arena -> New( + auto vp = arena -> New( context.SourceLoc(), std::nullopt, - global_arena->New(context.SourceLoc())); + arena->New(context.SourceLoc())); $$ = std::pair, Ptr>(vp, $3); } ; @@ -525,40 +522,39 @@ clause_list: ; statement: expression EQUAL expression SEMICOLON - { $$ = global_arena->New(context.SourceLoc(), $1, $3); } + { $$ = arena->New(context.SourceLoc(), $1, $3); } | VAR pattern EQUAL expression SEMICOLON - { $$ = global_arena->New(context.SourceLoc(), $2, $4); } + { $$ = arena->New(context.SourceLoc(), $2, $4); } | expression SEMICOLON - { $$ = global_arena->New(context.SourceLoc(), $1); } + { $$ = arena->New(context.SourceLoc(), $1); } | if_statement { $$ = $1; } | WHILE LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block - { $$ = global_arena->New(context.SourceLoc(), $3, $5); } + { $$ = arena->New(context.SourceLoc(), $3, $5); } | BREAK SEMICOLON - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | CONTINUE SEMICOLON - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } | RETURN return_expression SEMICOLON { auto [return_exp, is_omitted_exp] = $2.Release(); - $$ = global_arena->New(context.SourceLoc(), return_exp, - is_omitted_exp); + $$ = arena->New(context.SourceLoc(), return_exp, is_omitted_exp); } | block { $$ = $1; } | MATCH LEFT_PARENTHESIS expression RIGHT_PARENTHESIS LEFT_CURLY_BRACE clause_list RIGHT_CURLY_BRACE - { $$ = global_arena->New(context.SourceLoc(), $3, $6); } + { $$ = arena->New(context.SourceLoc(), $3, $6); } | CONTINUATION identifier statement - { $$ = global_arena->New(context.SourceLoc(), $2, $3); } + { $$ = arena->New(context.SourceLoc(), $2, $3); } | RUN expression SEMICOLON - { $$ = global_arena->New(context.SourceLoc(), $2); } + { $$ = arena->New(context.SourceLoc(), $2); } | AWAIT SEMICOLON - { $$ = global_arena->New(context.SourceLoc()); } + { $$ = arena->New(context.SourceLoc()); } ; if_statement: IF LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block optional_else - { $$ = global_arena->New(context.SourceLoc(), $3, $5, $6); } + { $$ = arena->New(context.SourceLoc(), $3, $5, $6); } ; optional_else: // Empty @@ -570,7 +566,7 @@ optional_else: ; return_expression: // Empty - { $$ = {global_arena->New(context.SourceLoc()), true}; } + { $$ = {arena->New(context.SourceLoc()), true}; } | expression { $$ = {$1, false}; } ; @@ -578,15 +574,15 @@ statement_list: // Empty { $$ = std::nullopt; } | statement statement_list - { $$ = global_arena->New(context.SourceLoc(), $1, $2); } + { $$ = arena->New(context.SourceLoc(), $1, $2); } ; block: LEFT_CURLY_BRACE statement_list RIGHT_CURLY_BRACE - { $$ = global_arena->New(context.SourceLoc(), $2); } + { $$ = arena->New(context.SourceLoc(), $2); } ; return_type: // Empty - { $$ = {global_arena->New(context.SourceLoc()), true}; } + { $$ = {arena->New(context.SourceLoc()), true}; } | ARROW expression %prec FNARROW { $$ = {$2, false}; } ; @@ -618,36 +614,36 @@ function_definition: FN identifier deduced_params maybe_empty_tuple_pattern return_type block { auto [return_exp, is_omitted_exp] = $5.Release(); - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), $2, $3, $4, - global_arena->New(return_exp), is_omitted_exp, $6); + arena->New(return_exp), is_omitted_exp, $6); } | FN identifier deduced_params maybe_empty_tuple_pattern DOUBLE_ARROW expression SEMICOLON { // The return type is not considered "omitted" because it's automatic from // the expression. - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), $2, $3, $4, - global_arena->New(context.SourceLoc()), true, - global_arena->New(context.SourceLoc(), $6, true)); + arena->New(context.SourceLoc()), true, + arena->New(context.SourceLoc(), $6, true)); } ; function_declaration: FN identifier deduced_params maybe_empty_tuple_pattern return_type SEMICOLON { auto [return_exp, is_omitted_exp] = $5.Release(); - $$ = global_arena->New( + $$ = arena->New( context.SourceLoc(), $2, $3, $4, - global_arena->New(return_exp), is_omitted_exp, + arena->New(return_exp), is_omitted_exp, std::nullopt); } ; variable_declaration: identifier COLON pattern - { $$ = global_arena->New(context.SourceLoc(), $1, $3); } + { $$ = arena->New(context.SourceLoc(), $1, $3); } ; member: VAR variable_declaration SEMICOLON - { $$ = global_arena->New(context.SourceLoc(), $2); } + { $$ = arena->New(context.SourceLoc(), $2); } ; member_list: // Empty @@ -664,7 +660,7 @@ alternative: | identifier { $$ = std::pair>( - $1, global_arena->New(context.SourceLoc())); + $1, arena->New(context.SourceLoc())); } ; alternative_list: @@ -686,17 +682,15 @@ alternative_list_contents: ; declaration: function_definition - { $$ = global_arena->New($1); } + { $$ = arena->New($1); } | function_declaration - { $$ = global_arena->New($1); } + { $$ = arena->New($1); } | CLASS identifier LEFT_CURLY_BRACE member_list RIGHT_CURLY_BRACE - { $$ = global_arena->New(context.SourceLoc(), $2, $4); } + { $$ = arena->New(context.SourceLoc(), $2, $4); } | CHOICE identifier LEFT_CURLY_BRACE alternative_list RIGHT_CURLY_BRACE - { $$ = global_arena->New(context.SourceLoc(), $2, $4); } + { $$ = arena->New(context.SourceLoc(), $2, $4); } | VAR variable_declaration EQUAL expression SEMICOLON - { - $$ = global_arena->New(context.SourceLoc(), $2, $4); - } + { $$ = arena->New(context.SourceLoc(), $2, $4); } ; declaration_list: // Empty