From 90f04700e25ee657871f20a8b1022d958cb45fc1 Mon Sep 17 00:00:00 2001 From: Jon Meow <46229924+jonmeow@users.noreply.github.com> Date: Thu, 9 Sep 2021 11:00:57 -0700 Subject: [PATCH] Remove global_arena (#814) With this, only main.cpp instantiates an arena. Maybe we'll want to split that up more later (e.g., so that the runtime interpreter uses its own arena), but given the intent to have type-checking update the AST, I thought this was a reasonable approach for now in order to avoid ownership complexities. Fixes #769 --- executable_semantics/ast/expression.cpp | 12 +- executable_semantics/ast/expression.h | 9 +- executable_semantics/ast/expression_test.cpp | 69 ++--- executable_semantics/ast/pattern.cpp | 20 +- executable_semantics/ast/pattern.h | 9 +- executable_semantics/ast/pattern_test.cpp | 53 ++-- executable_semantics/ast/statement.h | 4 +- executable_semantics/common/BUILD | 2 - executable_semantics/common/arena.cpp | 11 - executable_semantics/common/arena.h | 3 - executable_semantics/common/ptr.h | 5 + executable_semantics/interpreter/dictionary.h | 5 +- .../interpreter/exec_program.cpp | 39 ++- .../interpreter/exec_program.h | 2 +- executable_semantics/interpreter/heap.cpp | 24 +- executable_semantics/interpreter/heap.h | 7 +- .../interpreter/interpreter.cpp | 284 +++++++++--------- .../interpreter/interpreter.h | 11 + .../interpreter/type_checker.cpp | 270 ++++++++--------- .../interpreter/type_checker.h | 15 + executable_semantics/interpreter/value.cpp | 81 ++--- executable_semantics/interpreter/value.h | 12 +- executable_semantics/main.cpp | 5 +- executable_semantics/syntax/parse.cpp | 15 +- executable_semantics/syntax/parse.h | 5 +- .../syntax/parse_and_lex_context.h | 9 +- executable_semantics/syntax/parser.ypp | 168 +++++------ 27 files changed, 568 insertions(+), 581 deletions(-) delete mode 100644 executable_semantics/common/arena.cpp 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