From c7bbb412287789eda477daf5cd170ead032bf1d0 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Thu, 4 May 2023 15:55:52 +0000 Subject: [PATCH 01/29] Add framework for replacing lit with cc_test --- bazel/testing/lit_autoupdate_base.py | 3 +- bazel/testing/merge_output.py | 17 +- explorer/testdata/string/fail_newline.carbon | 2 +- .../fail_raw_more_hash_tags_on_left.carbon | 2 +- testing/file_test/BUILD | 29 +++ testing/file_test/example.carbon | 10 + testing/file_test/file_test_base.cpp | 218 ++++++++++++++++++ testing/file_test/file_test_base.h | 72 ++++++ testing/file_test/file_test_base_test.cpp | 44 ++++ testing/file_test/rules.bzl | 40 ++++ .../lowering/testdata/basics/zero.carbon | 2 +- .../function/definition/params_one.carbon | 2 +- .../function/definition/params_two.carbon | 2 +- .../function/definition/params_zero.carbon | 2 +- .../lowering/testdata/return/no_value.carbon | 2 +- .../lowering/testdata/return/value.carbon | 2 +- 16 files changed, 435 insertions(+), 14 deletions(-) create mode 100644 testing/file_test/BUILD create mode 100644 testing/file_test/example.carbon create mode 100644 testing/file_test/file_test_base.cpp create mode 100644 testing/file_test/file_test_base.h create mode 100644 testing/file_test/file_test_base_test.cpp create mode 100644 testing/file_test/rules.bzl diff --git a/bazel/testing/lit_autoupdate_base.py b/bazel/testing/lit_autoupdate_base.py index 013b656f581e0..36aaffbc7bd05 100755 --- a/bazel/testing/lit_autoupdate_base.py +++ b/bazel/testing/lit_autoupdate_base.py @@ -111,7 +111,8 @@ def parse_args() -> ParsedArgs: parser.add_argument( "--lit_run", metavar="COMMAND", - required=True, + default=[], + required=False, action="append", help="RUN lines to set.", ) diff --git a/bazel/testing/merge_output.py b/bazel/testing/merge_output.py index d5520fab7a0ff..5be6012efd949 100644 --- a/bazel/testing/merge_output.py +++ b/bazel/testing/merge_output.py @@ -8,7 +8,15 @@ import subprocess import sys -import textwrap + + +def _print(output: str, label: str) -> None: + if output: + for line in output.splitlines(): + if line: + print(f"{label}: {line}") + else: + print(f"{label}:") def main() -> None: @@ -18,10 +26,9 @@ def main() -> None: stderr=subprocess.PIPE, encoding="utf-8", ) - if p.stdout: - print(textwrap.indent(p.stdout, "STDOUT: "), end="") - if p.stderr: - print(textwrap.indent(p.stderr, "STDERR: "), end="") + # The `lambda line` forces prefixes on empty lines. + _print(p.stdout, "STDOUT") + _print(p.stderr, "STDERR") exit(p.returncode) diff --git a/explorer/testdata/string/fail_newline.carbon b/explorer/testdata/string/fail_newline.carbon index 53a1066399fc9..66c00629db3d5 100644 --- a/explorer/testdata/string/fail_newline.carbon +++ b/explorer/testdata/string/fail_newline.carbon @@ -10,7 +10,7 @@ package ExplorerTest api; fn Main() -> i32 { // CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_newline.carbon:[[@LINE+2]]: missing closing quote in single-line string: "new - // CHECK-EMPTY: + // CHECK:STDERR: Print("new line"); return 0; diff --git a/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon b/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon index 3cc3837fea0ff..1e0023af26b53 100644 --- a/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon +++ b/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon @@ -10,7 +10,7 @@ package ExplorerTest api; fn CompareStr(s: String) -> i32 { // CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/string/fail_raw_more_hash_tags_on_left.carbon:[[@LINE+2]]: missing closing quote in single-line string: ##"str"#) { - // CHECK-EMPTY: + // CHECK:STDERR: if (s == ##"str"#) { return 0; } diff --git a/testing/file_test/BUILD b/testing/file_test/BUILD new file mode 100644 index 0000000000000..c6ec62b9ee4b0 --- /dev/null +++ b/testing/file_test/BUILD @@ -0,0 +1,29 @@ +# 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 + +load("rules.bzl", "file_test") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "file_test_base", + srcs = ["file_test_base.cpp"], + hdrs = ["file_test_base.h"], + deps = [ + "//common:check", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) + +file_test( + name = "file_test", + srcs = ["file_test_base_test.cpp"], + tests = ["example.carbon"], + deps = [ + ":file_test_base", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) diff --git a/testing/file_test/example.carbon b/testing/file_test/example.carbon new file mode 100644 index 0000000000000..1f0301213f5b0 --- /dev/null +++ b/testing/file_test/example.carbon @@ -0,0 +1,10 @@ +// 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 + +// CHECK:STDOUT: something +// CHECK:STDOUT: +// CHECK:STDOUT: [[@LINE+1]]: Line delta +// CHECK:STDOUT: [[@LINE-1]]: Negative line delta +// CHECK:STDOUT: +*[]{} +// CHECK:STDOUT: F{{.+}}z diff --git a/testing/file_test/file_test_base.cpp b/testing/file_test/file_test_base.cpp new file mode 100644 index 0000000000000..0b4fe760cd4b0 --- /dev/null +++ b/testing/file_test/file_test_base.cpp @@ -0,0 +1,218 @@ +// 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 "testing/file_test/file_test_base.h" + +#include + +#include "common/check.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/InitLLVM.h" + +static std::string* subset_target = nullptr; + +namespace Carbon::Testing { + +void FileTestBase::RegisterTests( + const char* fixture_label, const std::vector& paths, + std::function factory) { + // Use RegisterTest instead of INSTANTIATE_TEST_CASE_P because of ordering + // issues between container initialization and test instantiation by + // InitGoogleTest. + for (auto path : paths) { + testing::RegisterTest(fixture_label, path.data(), nullptr, path.data(), + __FILE__, __LINE__, [=]() { return factory(path); }); + } +} + +// Splits outputs to string_view because gtest handles string_view by default. +static auto SplitOutput(llvm::StringRef output) + -> std::vector { + if (output.empty()) { + return {}; + } + llvm::SmallVector lines; + llvm::StringRef(output).split(lines, "\n"); + return std::vector(lines.begin(), lines.end()); +} + +// Runs a test and compares output. This keeps output split by line so that +// issues are a little easier to identify by the different line. +auto FileTestBase::TestBody() -> void { + llvm::errs() << "\nTo test this file alone, run:\n bazel test " + << *subset_target << " --test_arg=" << path() << "\n\n"; + + // Load expected output. + std::vector> expected_stdout; + std::vector> expected_stderr; + std::ifstream file_content(path_.str()); + int line_index = 0; + std::string line_str; + while (std::getline(file_content, line_str)) { + ++line_index; + llvm::StringRef line = line_str; + line = line.drop_while([](char c) { return c == ' '; }); + if (!line.consume_front("// CHECK")) { + continue; + } + if (line.consume_front(":STDOUT:")) { + expected_stdout.push_back(TransformExpectation(line_index, line)); + } else if (line.consume_front(":STDERR:")) { + expected_stderr.push_back(TransformExpectation(line_index, line)); + } else { + FAIL() << "Unexpected CHECK in input: " << line_str; + } + } + + // Assume there is always a suffix `\n` in output. + if (!expected_stdout.empty()) { + expected_stdout.push_back(testing::StrEq("")); + } + if (!expected_stderr.empty()) { + expected_stderr.push_back(testing::StrEq("")); + } + + // Capture trace streaming, but only when in debug mode. + std::string stdout; + std::string stderr; + llvm::raw_string_ostream stdout_ostream(stdout); + llvm::raw_string_ostream stderr_ostream(stderr); + RunOverFile(stdout_ostream, stderr_ostream); + if (HasFailure()) { + return; + } + + // Check results. + EXPECT_THAT(SplitOutput(stdout), ElementsAreArray(expected_stdout)); + EXPECT_THAT(SplitOutput(stderr), ElementsAreArray(expected_stderr)); +} + +auto FileTestBase::TransformExpectation(int line_index, llvm::StringRef in) + -> testing::Matcher { + if (in.empty()) { + return testing::StrEq(""); + } + CARBON_CHECK(in[0] == ' ') << "Malformated input: " << in; + std::string str = in.substr(1).str(); + for (int pos = 0; pos < static_cast(str.size());) { + switch (str[pos]) { + case '(': + case ')': + case ']': + case '}': + case '.': + case '^': + case '$': + case '*': + case '+': + case '?': + case '|': + case '\\': { + // Escape regex characters. + str.insert(pos, "\\"); + pos += 2; + break; + } + case '[': { + static constexpr llvm::StringLiteral LineKeyword = "[[@LINE"; + llvm::StringRef line_keyword_cursor = llvm::StringRef(str).substr(pos); + if (line_keyword_cursor.consume_front(LineKeyword)) { + // Allow + or - here; consumeInteger handles -. + line_keyword_cursor.consume_front("+"); + int offset; + // consumeInteger returns true for errors, not false. + CARBON_CHECK(!line_keyword_cursor.consumeInteger(10, offset) && + line_keyword_cursor.consume_front("]]")) + << "Unexpected @LINE offset at `" + << line_keyword_cursor.substr(0, 5) << "` in: " << in; + std::string int_str = llvm::Twine(line_index + offset).str(); + int remove_len = (line_keyword_cursor.data() - str.data()) - pos; + str.replace(pos, remove_len, int_str); + pos += int_str.size(); + } else { + // Escape the `[`. + str.insert(pos, "\\"); + pos += 2; + } + break; + } + case '{': { + static constexpr llvm::StringLiteral PathBefore = "{{.*}}/explorer/"; + static constexpr llvm::StringLiteral PathAfter = "explorer/"; + if (pos + 1 == static_cast(str.size()) || str[pos + 1] != '{') { + // Single `{`, escape it. + str.insert(pos, "\\"); + pos += 2; + } else if (llvm::StringRef(str).substr(pos).starts_with(PathBefore)) { + str.replace(pos, PathBefore.size(), PathAfter); + // Move the position; the loop still increments position by 1. + pos += PathAfter.size(); + } else { + // Replace the `{{...}}` regex syntax with standard `(...)` syntax. + str.replace(pos, 2, "("); + for (++pos; pos < static_cast(str.size() - 1); ++pos) { + if (str[pos] == '}' && str[pos + 1] == '}') { + str.replace(pos, 2, ")"); + ++pos; + break; + } + } + } + break; + } + default: { + ++pos; + } + } + } + + return testing::MatchesRegex(str); +} + +auto FileTestBase::filename() -> llvm::StringRef { + auto last_slash = path_.rfind("/"); + if (last_slash == llvm::StringRef::npos) { + return path_; + } else { + return path_.substr(last_slash + 1); + } +} + +} // namespace Carbon::Testing + +// Returns the name of the subset target. +static auto GetSubsetTarget() -> std::string { + char* name = getenv("TEST_TARGET"); + if (name == nullptr) { + return ""; + } + + if (llvm::StringRef(name).ends_with(".subset")) { + return name; + } else { + return std::string(name) + ".subset"; + } +} + +auto main(int argc, char** argv) -> int { + testing::InitGoogleTest(&argc, argv); + llvm::setBugReportMsg( + "Please report issues to " + "https://github.com/carbon-language/carbon-lang/issues and include the " + "crash backtrace.\n"); + llvm::InitLLVM init_llvm(argc, argv); + + if (argc < 2) { + llvm::errs() << "At least one test file must be provided.\n"; + return EXIT_FAILURE; + } + + std::string subset_target_storage = GetSubsetTarget(); + ::subset_target = &subset_target_storage; + + std::vector paths(argv + 1, argv + argc); + Carbon::Testing::RegisterFileTests(paths); + + return RUN_ALL_TESTS(); +} diff --git a/testing/file_test/file_test_base.h b/testing/file_test/file_test_base.h new file mode 100644 index 0000000000000..da3e79bba571b --- /dev/null +++ b/testing/file_test/file_test_base.h @@ -0,0 +1,72 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TESTING_FILE_TEST_FILE_TEST_BASE_H_ +#define CARBON_TESTING_FILE_TEST_FILE_TEST_BASE_H_ + +#include +#include + +#include +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +namespace Carbon::Testing { + +// A framework for testing files. Children implement `RegisterTestFiles` with +// calls to `RegisterTests` using a factory that constructs the child. +// `RunOverFile` must also be implemented and will be called as part of +// individual test executions. This framework includes a `main` implementation, +// so users must not provide one. +// +// Tests should have CHECK lines similar to `FileCheck` syntax: +// https://llvm.org/docs/CommandGuide/FileCheck.html +// +// Special nuances are that stdout and stderr will look like `// CHECK:STDOUT: +// ...` and `// CHECK:STDERR: ...` respectively. `[[@LINE+offset]` and +// `{{regex}}` syntaxes should also work. +// +// `lit_autoupdate.py` automatically constructs compatible lines. +class FileTestBase : public testing::Test { + public: + explicit FileTestBase(const llvm::StringRef path) : path_(path) {} + + // Used by children to register tests with gtest. + static void RegisterTests( + const char* fixture_label, const std::vector& paths, + std::function factory); + + // Implemented by children to run the test. Called by the TestBody + // implementation, which will validate stdout and stderr. + virtual auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) + -> void = 0; + + // Runs a test and compares output. This keeps output split by line so that + // issues are a little easier to identify by the different line. + auto TestBody() -> void final; + + // Returns the filename of the file being tested. + auto filename() -> llvm::StringRef; + + // Returns the full path of the file being tested. + auto path() -> llvm::StringRef { return path_; }; + + private: + // Transforms an expectation on a given line from `FileCheck` syntax into a + // standard regex matcher. + static auto TransformExpectation(int line_index, llvm::StringRef in) + -> testing::Matcher; + + llvm::StringRef path_; +}; + +// Must be implemented by the individual file_test to initialize tests. +extern auto RegisterFileTests(const std::vector& paths) + -> void; + +} // namespace Carbon::Testing + +#endif // CARBON_TESTING_FILE_TEST_FILE_TEST_BASE_H_ diff --git a/testing/file_test/file_test_base_test.cpp b/testing/file_test/file_test_base_test.cpp new file mode 100644 index 0000000000000..437f7793e5260 --- /dev/null +++ b/testing/file_test/file_test_base_test.cpp @@ -0,0 +1,44 @@ +// 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 "testing/file_test/file_test_base.h" + +#include +#include + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +namespace Carbon::Testing { +namespace { + +class FileTestBaseTest : public FileTestBase { + public: + explicit FileTestBaseTest(llvm::StringRef path) : FileTestBase(path) {} + + void RunOverFile(llvm::raw_ostream& stdout_stream, + llvm::raw_ostream& /*stderr*/) override { + ASSERT_THAT(filename(), testing::StrEq("example.carbon")); + + stdout_stream << "something\n" + "\n" + "8: Line delta\n" + "7: Negative line delta\n" + "+*[]{}\n" + "Foo baz\n"; + } +}; + +} // namespace + +auto RegisterFileTests(const std::vector& paths) -> void { + Carbon::Testing::FileTestBaseTest::RegisterTests( + "FileTestBaseTest", paths, [](llvm::StringRef path) { + return new Carbon::Testing::FileTestBaseTest(path); + }); +} + +} // namespace Carbon::Testing diff --git a/testing/file_test/rules.bzl b/testing/file_test/rules.bzl new file mode 100644 index 0000000000000..8cfa914a1a37e --- /dev/null +++ b/testing/file_test/rules.bzl @@ -0,0 +1,40 @@ +# 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 + +"""Rules for building fuzz tests.""" + +load("@bazel_skylib//rules:native_binary.bzl", "native_test") + +def file_test(name, srcs, deps, tests, shard_count = 1): + """Generates tests using the file_test base. + + There will be one main test using `name` that can be sharded, and includes + all files. Additionally, per-file tests will be generated as + `name.file_path`; these per-file tests will be manual. + + Args: + name: The base name of the tests. + srcs: cc_test srcs. + deps: cc_test deps. + tests: The list of test files to use as data. + shard_count: The number of shards to use; defaults to 1. + """ + subset_name = "{0}.subset".format(name) + + native.cc_test( + name = name, + srcs = srcs, + deps = deps, + data = tests, + args = ["$(location {0})".format(x) for x in tests], + shard_count = shard_count, + ) + + native_test( + name = subset_name, + src = name, + out = subset_name, + data = tests, + tags = ["manual"], + ) diff --git a/toolchain/lowering/testdata/basics/zero.carbon b/toolchain/lowering/testdata/basics/zero.carbon index 26ad83f6bce5a..186f64c6d6bf8 100644 --- a/toolchain/lowering/testdata/basics/zero.carbon +++ b/toolchain/lowering/testdata/basics/zero.carbon @@ -6,7 +6,7 @@ // RUN: %{carbon-run-lowering} // CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/basics/zero.carbon' // CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/basics/zero.carbon" -// CHECK-EMPTY: +// CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret i32 0 diff --git a/toolchain/lowering/testdata/function/definition/params_one.carbon b/toolchain/lowering/testdata/function/definition/params_one.carbon index dcab7e1f9495d..106a70f7ed4ce 100644 --- a/toolchain/lowering/testdata/function/definition/params_one.carbon +++ b/toolchain/lowering/testdata/function/definition/params_one.carbon @@ -6,7 +6,7 @@ // RUN: %{carbon-run-lowering} // CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/function/definition/params_one.carbon' // CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/function/definition/params_one.carbon" -// CHECK-EMPTY: +// CHECK:STDOUT: // CHECK:STDOUT: define void @Foo(i32 %a) { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/definition/params_two.carbon b/toolchain/lowering/testdata/function/definition/params_two.carbon index c090c0bc93dbe..3af7b7e1e4303 100644 --- a/toolchain/lowering/testdata/function/definition/params_two.carbon +++ b/toolchain/lowering/testdata/function/definition/params_two.carbon @@ -6,7 +6,7 @@ // RUN: %{carbon-run-lowering} // CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/function/definition/params_two.carbon' // CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/function/definition/params_two.carbon" -// CHECK-EMPTY: +// CHECK:STDOUT: // CHECK:STDOUT: define void @Foo(i32 %a, i32 %b) { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/definition/params_zero.carbon b/toolchain/lowering/testdata/function/definition/params_zero.carbon index ff92d1e0aaa27..3de6972bac592 100644 --- a/toolchain/lowering/testdata/function/definition/params_zero.carbon +++ b/toolchain/lowering/testdata/function/definition/params_zero.carbon @@ -6,7 +6,7 @@ // RUN: %{carbon-run-lowering} // CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/function/definition/params_zero.carbon' // CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/function/definition/params_zero.carbon" -// CHECK-EMPTY: +// CHECK:STDOUT: // CHECK:STDOUT: define void @Foo() { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/return/no_value.carbon b/toolchain/lowering/testdata/return/no_value.carbon index ad7b4ff02cd6e..fff9cb9e4e50d 100644 --- a/toolchain/lowering/testdata/return/no_value.carbon +++ b/toolchain/lowering/testdata/return/no_value.carbon @@ -6,7 +6,7 @@ // RUN: %{carbon-run-lowering} // CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/return/no_value.carbon' // CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/return/no_value.carbon" -// CHECK-EMPTY: +// CHECK:STDOUT: // CHECK:STDOUT: define void @Main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void diff --git a/toolchain/lowering/testdata/return/value.carbon b/toolchain/lowering/testdata/return/value.carbon index a0514dc6b97bd..a2ce60b9c91ae 100644 --- a/toolchain/lowering/testdata/return/value.carbon +++ b/toolchain/lowering/testdata/return/value.carbon @@ -6,7 +6,7 @@ // RUN: %{carbon-run-lowering} // CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/return/value.carbon' // CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/return/value.carbon" -// CHECK-EMPTY: +// CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret i32 0 From d9633111f96bfbf8e8de19d5496a24506b6c0ff0 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Thu, 4 May 2023 21:16:56 +0000 Subject: [PATCH 02/29] Refactor parser logic into separate files. --- toolchain/parser/BUILD | 21 +- toolchain/parser/parse_tree.cpp | 27 +- toolchain/parser/parse_tree.h | 6 +- toolchain/parser/parser.cpp | 1968 ----------------- toolchain/parser/parser_context.cpp | 457 ++++ .../parser/{parser.h => parser_context.h} | 159 +- .../parser/parser_handle_brace_expression.cpp | 230 ++ .../parser/parser_handle_call_expression.cpp | 46 + toolchain/parser/parser_handle_code_block.cpp | 42 + ...ser_handle_declaration_name_and_params.cpp | 62 + .../parser_handle_declaration_scope_loop.cpp | 65 + toolchain/parser/parser_handle_designator.cpp | 49 + toolchain/parser/parser_handle_expression.cpp | 227 ++ toolchain/parser/parser_handle_function.cpp | 99 + toolchain/parser/parser_handle_package.cpp | 94 + toolchain/parser/parser_handle_parameter.cpp | 109 + .../parser/parser_handle_paren_condition.cpp | 45 + .../parser/parser_handle_paren_expression.cpp | 84 + toolchain/parser/parser_handle_pattern.cpp | 142 ++ toolchain/parser/parser_handle_statement.cpp | 225 ++ toolchain/parser/parser_handle_states.h | 20 + toolchain/parser/parser_handle_type.cpp | 122 + toolchain/parser/parser_handle_var.cpp | 88 + 23 files changed, 2304 insertions(+), 2083 deletions(-) delete mode 100644 toolchain/parser/parser.cpp create mode 100644 toolchain/parser/parser_context.cpp rename toolchain/parser/{parser.h => parser_context.h} (71%) create mode 100644 toolchain/parser/parser_handle_brace_expression.cpp create mode 100644 toolchain/parser/parser_handle_call_expression.cpp create mode 100644 toolchain/parser/parser_handle_code_block.cpp create mode 100644 toolchain/parser/parser_handle_declaration_name_and_params.cpp create mode 100644 toolchain/parser/parser_handle_declaration_scope_loop.cpp create mode 100644 toolchain/parser/parser_handle_designator.cpp create mode 100644 toolchain/parser/parser_handle_expression.cpp create mode 100644 toolchain/parser/parser_handle_function.cpp create mode 100644 toolchain/parser/parser_handle_package.cpp create mode 100644 toolchain/parser/parser_handle_parameter.cpp create mode 100644 toolchain/parser/parser_handle_paren_condition.cpp create mode 100644 toolchain/parser/parser_handle_paren_expression.cpp create mode 100644 toolchain/parser/parser_handle_pattern.cpp create mode 100644 toolchain/parser/parser_handle_statement.cpp create mode 100644 toolchain/parser/parser_handle_states.h create mode 100644 toolchain/parser/parser_handle_type.cpp create mode 100644 toolchain/parser/parser_handle_var.cpp diff --git a/toolchain/parser/BUILD b/toolchain/parser/BUILD index 3f7b73d2c74a8..e3582d5feaa7f 100644 --- a/toolchain/parser/BUILD +++ b/toolchain/parser/BUILD @@ -29,8 +29,25 @@ cc_library( name = "parse_tree", srcs = [ "parse_tree.cpp", - "parser.cpp", - "parser.h", + "parser_context.cpp", + "parser_context.h", + "parser_handle_brace_expression.cpp", + "parser_handle_call_expression.cpp", + "parser_handle_code_block.cpp", + "parser_handle_declaration_name_and_params.cpp", + "parser_handle_declaration_scope_loop.cpp", + "parser_handle_designator.cpp", + "parser_handle_expression.cpp", + "parser_handle_function.cpp", + "parser_handle_package.cpp", + "parser_handle_parameter.cpp", + "parser_handle_paren_condition.cpp", + "parser_handle_paren_expression.cpp", + "parser_handle_pattern.cpp", + "parser_handle_statement.cpp", + "parser_handle_states.h", + "parser_handle_type.cpp", + "parser_handle_var.cpp", ], hdrs = ["parse_tree.h"], deps = [ diff --git a/toolchain/parser/parse_tree.cpp b/toolchain/parser/parse_tree.cpp index f6d5cfefb7af3..b6e6da731a284 100644 --- a/toolchain/parser/parse_tree.cpp +++ b/toolchain/parser/parse_tree.cpp @@ -13,7 +13,8 @@ #include "llvm/ADT/SmallVector.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" -#include "toolchain/parser/parser.h" +#include "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" namespace Carbon { @@ -24,7 +25,29 @@ auto ParseTree::Parse(TokenizedBuffer& tokens, DiagnosticConsumer& consumer, TokenDiagnosticEmitter emitter(translator, consumer); // Delegate to the parser. - auto tree = Parser::Parse(tokens, emitter, vlog_stream); + ParseTree tree(tokens); + ParserContext context(tree, tokens, emitter, vlog_stream); + + context.PushState(ParserState::DeclarationScopeLoop); + + // The package should always be the first token, if it's present. Any other + // use is invalid. + if (context.PositionIs(TokenKind::Package)) { + context.PushState(ParserState::Package); + } + + while (!context.state_stack().empty()) { + switch (context.state_stack().back().state) { +#define CARBON_PARSER_STATE(Name) \ + case ParserState::Name: \ + ParserHandle##Name(context); \ + break; +#include "toolchain/parser/parser_state.def" + } + } + + context.AddLeafNode(ParseNodeKind::FileEnd, *context.position()); + if (auto verify = tree.Verify(); !verify.ok()) { if (vlog_stream) { tree.Print(*vlog_stream); diff --git a/toolchain/parser/parse_tree.h b/toolchain/parser/parse_tree.h index c340b01553172..b9934c3cc930a 100644 --- a/toolchain/parser/parse_tree.h +++ b/toolchain/parser/parse_tree.h @@ -149,7 +149,7 @@ class ParseTree { [[nodiscard]] auto Verify() const -> ErrorOr; private: - friend class Parser; + friend class ParserContext; // The in-memory representation of data used for a particular node in the // tree. @@ -205,8 +205,8 @@ class ParseTree { static_assert(sizeof(NodeImpl) == 12, "Unexpected size of node implementation!"); - // Wires up the reference to the tokenized buffer. The global `parse` routine - // should be used to actually parse the tokens into a tree. + // Wires up the reference to the tokenized buffer. The `Parse` function should + // be used to actually parse the tokens into a tree. explicit ParseTree(TokenizedBuffer& tokens_arg) : tokens_(&tokens_arg) { // If the tree is valid, there will be one node per token, so reserve once. node_impls_.reserve(tokens_->size()); diff --git a/toolchain/parser/parser.cpp b/toolchain/parser/parser.cpp deleted file mode 100644 index 4e5d6be839633..0000000000000 --- a/toolchain/parser/parser.cpp +++ /dev/null @@ -1,1968 +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 "toolchain/parser/parser.h" - -#include -#include -#include - -#include "common/check.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "toolchain/lexer/token_kind.h" -#include "toolchain/lexer/tokenized_buffer.h" -#include "toolchain/parser/parse_node_kind.h" -#include "toolchain/parser/parse_tree.h" - -namespace Carbon { - -// May be emitted a couple different ways as part of operator parsing. -CARBON_DIAGNOSTIC( - OperatorRequiresParentheses, Error, - "Parentheses are required to disambiguate operator precedence."); - -CARBON_DIAGNOSTIC(ExpectedSemiAfterExpression, Error, - "Expected `;` after expression."); - -CARBON_DIAGNOSTIC(ExpectedDeclarationName, Error, - "`{0}` introducer should be followed by a name.", TokenKind); -CARBON_DIAGNOSTIC(ExpectedDeclarationSemiOrDefinition, Error, - "`{0}` should either end with a `;` for a declaration or " - "have a `{{ ... }` block for a definition.", - TokenKind); - -// A relative location for characters in errors. -enum class RelativeLocation : int8_t { - Around, - After, - Before, -}; - -// Adapts RelativeLocation for use with formatv. -static auto operator<<(llvm::raw_ostream& out, RelativeLocation loc) - -> llvm::raw_ostream& { - switch (loc) { - case RelativeLocation::Around: - out << "around"; - break; - case RelativeLocation::After: - out << "after"; - break; - case RelativeLocation::Before: - out << "before"; - break; - } - return out; -} - -class Parser::PrettyStackTraceParseState : public llvm::PrettyStackTraceEntry { - public: - explicit PrettyStackTraceParseState(const Parser* parser) : parser_(parser) {} - ~PrettyStackTraceParseState() override = default; - - auto print(llvm::raw_ostream& output) const -> void override { - output << "Parser stack:\n"; - for (int i = 0; i < static_cast(parser_->state_stack_.size()); ++i) { - const auto& entry = parser_->state_stack_[i]; - output << "\t" << i << ".\t" << entry.state; - Print(output, entry.token); - } - output << "\tcursor\tposition_"; - Print(output, *parser_->position_); - } - - private: - auto Print(llvm::raw_ostream& output, TokenizedBuffer::Token token) const - -> void { - auto line = parser_->tokens_->GetLine(token); - output << " @ " << parser_->tokens_->GetLineNumber(line) << ":" - << parser_->tokens_->GetColumnNumber(token) << ":" - << " token " << token << " : " << parser_->tokens_->GetKind(token) - << "\n"; - } - - const Parser* parser_; -}; - -Parser::Parser(ParseTree& tree, TokenizedBuffer& tokens, - TokenDiagnosticEmitter& emitter, llvm::raw_ostream* vlog_stream) - : tree_(&tree), - tokens_(&tokens), - emitter_(&emitter), - vlog_stream_(vlog_stream), - position_(tokens_->tokens().begin()), - end_(tokens_->tokens().end()) { - CARBON_CHECK(position_ != end_) << "Empty TokenizedBuffer"; - --end_; - CARBON_CHECK(tokens_->GetKind(*end_) == TokenKind::EndOfFile) - << "TokenizedBuffer should end with EndOfFile, ended with " - << tokens_->GetKind(*end_); -} - -auto Parser::AddLeafNode(ParseNodeKind kind, TokenizedBuffer::Token token, - bool has_error) -> void { - tree_->node_impls_.push_back( - ParseTree::NodeImpl(kind, has_error, token, /*subtree_size=*/1)); - if (has_error) { - tree_->has_errors_ = true; - } -} - -auto Parser::AddNode(ParseNodeKind kind, TokenizedBuffer::Token token, - int subtree_start, bool has_error) -> void { - int subtree_size = tree_->size() - subtree_start + 1; - tree_->node_impls_.push_back( - ParseTree::NodeImpl(kind, has_error, token, subtree_size)); - if (has_error) { - tree_->has_errors_ = true; - } -} - -auto Parser::ConsumeAndAddOpenParen(TokenizedBuffer::Token default_token, - ParseNodeKind start_kind) -> void { - if (auto open_paren = ConsumeIf(TokenKind::OpenParen)) { - AddLeafNode(start_kind, *open_paren, /*has_error=*/false); - } else { - CARBON_DIAGNOSTIC(ExpectedParenAfter, Error, "Expected `(` after `{0}`.", - TokenKind); - emitter_->Emit(*position_, ExpectedParenAfter, - tokens_->GetKind(default_token)); - AddLeafNode(start_kind, default_token, /*has_error=*/true); - } -} - -auto Parser::ConsumeAndAddCloseParen(StateStackEntry state, - ParseNodeKind close_kind) -> void { - // state.token should point at the introducer, with the paren one after the - // introducer. - auto expected_paren = *(TokenizedBuffer::TokenIterator(state.token) + 1); - - if (tokens_->GetKind(expected_paren) != TokenKind::OpenParen) { - AddNode(close_kind, state.token, state.subtree_start, /*has_error=*/true); - } else if (auto close_token = ConsumeIf(TokenKind::CloseParen)) { - AddNode(close_kind, *close_token, state.subtree_start, state.has_error); - } else { - // TODO: Include the location of the matching open_paren in the diagnostic. - CARBON_DIAGNOSTIC(ExpectedCloseParen, Error, - "Unexpected tokens before `)`."); - emitter_->Emit(*position_, ExpectedCloseParen); - - SkipTo(tokens_->GetMatchedClosingToken(expected_paren)); - AddNode(close_kind, Consume(), state.subtree_start, /*has_error=*/true); - } -} - -auto Parser::ConsumeAndAddLeafNodeIf(TokenKind token_kind, - ParseNodeKind node_kind) -> bool { - auto token = ConsumeIf(token_kind); - if (!token) { - return false; - } - - AddLeafNode(node_kind, *token); - return true; -} - -auto Parser::ConsumeChecked(TokenKind kind) -> TokenizedBuffer::Token { - CARBON_CHECK(PositionIs(kind)) - << "Required " << kind << ", found " << PositionKind(); - return Consume(); -} - -auto Parser::ConsumeIf(TokenKind kind) - -> std::optional { - if (!PositionIs(kind)) { - return std::nullopt; - } - return Consume(); -} - -auto Parser::FindNextOf(std::initializer_list desired_kinds) - -> std::optional { - auto new_position = position_; - while (true) { - TokenizedBuffer::Token token = *new_position; - TokenKind kind = tokens_->GetKind(token); - if (kind.IsOneOf(desired_kinds)) { - return token; - } - - // Step to the next token at the current bracketing level. - if (kind.is_closing_symbol() || kind == TokenKind::EndOfFile) { - // There are no more tokens at this level. - return std::nullopt; - } else if (kind.is_opening_symbol()) { - new_position = TokenizedBuffer::TokenIterator( - tokens_->GetMatchedClosingToken(token)); - // Advance past the closing token. - ++new_position; - } else { - ++new_position; - } - } -} - -auto Parser::SkipMatchingGroup() -> bool { - if (!PositionKind().is_opening_symbol()) { - return false; - } - - SkipTo(tokens_->GetMatchedClosingToken(*position_)); - ++position_; - return true; -} - -auto Parser::SkipPastLikelyEnd(TokenizedBuffer::Token skip_root) - -> std::optional { - if (position_ == end_) { - return std::nullopt; - } - - TokenizedBuffer::Line root_line = tokens_->GetLine(skip_root); - int root_line_indent = tokens_->GetIndentColumnNumber(root_line); - - // We will keep scanning through tokens on the same line as the root or - // lines with greater indentation than root's line. - auto is_same_line_or_indent_greater_than_root = - [&](TokenizedBuffer::Token t) { - TokenizedBuffer::Line l = tokens_->GetLine(t); - if (l == root_line) { - return true; - } - - return tokens_->GetIndentColumnNumber(l) > root_line_indent; - }; - - do { - if (PositionIs(TokenKind::CloseCurlyBrace)) { - // Immediately bail out if we hit an unmatched close curly, this will - // pop us up a level of the syntax grouping. - return std::nullopt; - } - - // We assume that a semicolon is always intended to be the end of the - // current construct. - if (auto semi = ConsumeIf(TokenKind::Semi)) { - return semi; - } - - // Skip over any matching group of tokens_-> - if (SkipMatchingGroup()) { - continue; - } - - // Otherwise just step forward one token. - ++position_; - } while (position_ != end_ && - is_same_line_or_indent_greater_than_root(*position_)); - - return std::nullopt; -} - -auto Parser::SkipTo(TokenizedBuffer::Token t) -> void { - CARBON_CHECK(t >= *position_) << "Tried to skip backwards from " << position_ - << " to " << TokenizedBuffer::TokenIterator(t); - position_ = TokenizedBuffer::TokenIterator(t); - CARBON_CHECK(position_ != end_) << "Skipped past EOF."; -} - -auto Parser::HandleCodeBlockState() -> void { - PopAndDiscardState(); - - PushState(ParserState::CodeBlockFinish); - if (ConsumeAndAddLeafNodeIf(TokenKind::OpenCurlyBrace, - ParseNodeKind::CodeBlockStart)) { - PushState(ParserState::StatementScopeLoop); - } else { - AddLeafNode(ParseNodeKind::CodeBlockStart, *position_, - /*has_error=*/true); - - // Recover by parsing a single statement. - CARBON_DIAGNOSTIC(ExpectedCodeBlock, Error, "Expected braced code block."); - emitter_->Emit(*position_, ExpectedCodeBlock); - - PushState(ParserState::Statement); - } -} - -// Determines whether the given token is considered to be the start of an -// operand according to the rules for infix operator parsing. -static auto IsAssumedStartOfOperand(TokenKind kind) -> bool { - return kind.IsOneOf({TokenKind::OpenParen, TokenKind::Identifier, - TokenKind::IntegerLiteral, TokenKind::RealLiteral, - TokenKind::StringLiteral}); -} - -// Determines whether the given token is considered to be the end of an -// operand according to the rules for infix operator parsing. -static auto IsAssumedEndOfOperand(TokenKind kind) -> bool { - return kind.IsOneOf({TokenKind::CloseParen, TokenKind::CloseCurlyBrace, - TokenKind::CloseSquareBracket, TokenKind::Identifier, - TokenKind::IntegerLiteral, TokenKind::RealLiteral, - TokenKind::StringLiteral}); -} - -// Determines whether the given token could possibly be the start of an -// operand. This is conservatively correct, and will never incorrectly return -// `false`, but can incorrectly return `true`. -static auto IsPossibleStartOfOperand(TokenKind kind) -> bool { - return !kind.IsOneOf({TokenKind::CloseParen, TokenKind::CloseCurlyBrace, - TokenKind::CloseSquareBracket, TokenKind::Comma, - TokenKind::Semi, TokenKind::Colon}); -} - -auto Parser::IsLexicallyValidInfixOperator() -> bool { - CARBON_CHECK(position_ != end_) << "Expected an operator token."; - - bool leading_space = tokens_->HasLeadingWhitespace(*position_); - bool trailing_space = tokens_->HasTrailingWhitespace(*position_); - - // If there's whitespace on both sides, it's an infix operator. - if (leading_space && trailing_space) { - return true; - } - - // If there's whitespace on exactly one side, it's not an infix operator. - if (leading_space || trailing_space) { - return false; - } - - // Otherwise, for an infix operator, the preceding token must be any close - // bracket, identifier, or literal and the next token must be an open paren, - // identifier, or literal. - if (position_ == tokens_->tokens().begin() || - !IsAssumedEndOfOperand(tokens_->GetKind(*(position_ - 1))) || - !IsAssumedStartOfOperand(tokens_->GetKind(*(position_ + 1)))) { - return false; - } - - return true; -} - -auto Parser::IsTrailingOperatorInfix() -> bool { - if (position_ == end_) { - return false; - } - - // An operator that follows the infix operator rules is parsed as - // infix, unless the next token means that it can't possibly be. - if (IsLexicallyValidInfixOperator() && - IsPossibleStartOfOperand(tokens_->GetKind(*(position_ + 1)))) { - return true; - } - - // A trailing operator with leading whitespace that's not valid as infix is - // not valid at all. If the next token looks like the start of an operand, - // then parse as infix, otherwise as postfix. Either way we'll produce a - // diagnostic later on. - if (tokens_->HasLeadingWhitespace(*position_) && - IsAssumedStartOfOperand(tokens_->GetKind(*(position_ + 1)))) { - return true; - } - - return false; -} - -auto Parser::DiagnoseOperatorFixity(OperatorFixity fixity) -> void { - if (fixity == OperatorFixity::Infix) { - // Infix operators must satisfy the infix operator rules. - if (!IsLexicallyValidInfixOperator()) { - CARBON_DIAGNOSTIC(BinaryOperatorRequiresWhitespace, Error, - "Whitespace missing {0} binary operator.", - RelativeLocation); - emitter_->Emit(*position_, BinaryOperatorRequiresWhitespace, - tokens_->HasLeadingWhitespace(*position_) - ? RelativeLocation::After - : (tokens_->HasTrailingWhitespace(*position_) - ? RelativeLocation::Before - : RelativeLocation::Around)); - } - } else { - bool prefix = fixity == OperatorFixity::Prefix; - - // Whitespace is not permitted between a symbolic pre/postfix operator and - // its operand. - if (PositionKind().is_symbol() && - (prefix ? tokens_->HasTrailingWhitespace(*position_) - : tokens_->HasLeadingWhitespace(*position_))) { - CARBON_DIAGNOSTIC(UnaryOperatorHasWhitespace, Error, - "Whitespace is not allowed {0} this unary operator.", - RelativeLocation); - emitter_->Emit( - *position_, UnaryOperatorHasWhitespace, - prefix ? RelativeLocation::After : RelativeLocation::Before); - } - // Pre/postfix operators must not satisfy the infix operator rules. - if (IsLexicallyValidInfixOperator()) { - CARBON_DIAGNOSTIC(UnaryOperatorRequiresWhitespace, Error, - "Whitespace is required {0} this unary operator.", - RelativeLocation); - emitter_->Emit( - *position_, UnaryOperatorRequiresWhitespace, - prefix ? RelativeLocation::Before : RelativeLocation::After); - } - } -} - -auto Parser::ConsumeListToken(ParseNodeKind comma_kind, TokenKind close_kind, - bool already_has_error) -> ListTokenKind { - if (!PositionIs(TokenKind::Comma) && !PositionIs(close_kind)) { - // Don't error a second time on the same element. - if (!already_has_error) { - CARBON_DIAGNOSTIC(UnexpectedTokenAfterListElement, Error, - "Expected `,` or `{0}`.", TokenKind); - emitter_->Emit(*position_, UnexpectedTokenAfterListElement, close_kind); - ReturnErrorOnState(); - } - - // Recover from the invalid token. - auto end_of_element = FindNextOf({TokenKind::Comma, close_kind}); - // The lexer guarantees that parentheses are balanced. - CARBON_CHECK(end_of_element) - << "missing matching `" << close_kind.opening_symbol() << "` for `" - << close_kind << "`"; - - SkipTo(*end_of_element); - } - - if (PositionIs(close_kind)) { - return ListTokenKind::Close; - } else { - AddLeafNode(comma_kind, Consume()); - return PositionIs(close_kind) ? ListTokenKind::CommaClose - : ListTokenKind::Comma; - } -} - -auto Parser::Parse() -> void { - // Traces state_stack_. This runs even in opt because it's low overhead. - PrettyStackTraceParseState pretty_stack(this); - - PushState(ParserState::DeclarationScopeLoop); - - // The package should always be the first token, if it's present. Any other - // use is invalid. - if (PositionIs(TokenKind::Package)) { - PushState(ParserState::Package); - } - - while (!state_stack_.empty()) { - switch (state_stack_.back().state) { -#define CARBON_PARSER_STATE(Name) \ - case ParserState::Name: \ - Handle##Name##State(); \ - break; -#include "toolchain/parser/parser_state.def" - } - } - - AddLeafNode(ParseNodeKind::FileEnd, *position_); -} - -auto Parser::GetDeclarationContext() -> DeclarationContext { - // i == 0 is the file-level DeclarationScopeLoop. Additionally, i == 1 can be - // skipped because it will never be a DeclarationScopeLoop. - for (int i = state_stack_.size() - 1; i > 1; --i) { - // The declaration context is always the state _above_ a - // DeclarationScopeLoop. - if (state_stack_[i].state == ParserState::DeclarationScopeLoop) { - switch (state_stack_[i - 1].state) { - case ParserState::TypeDefinitionFinishAsClass: - return DeclarationContext::Class; - case ParserState::TypeDefinitionFinishAsInterface: - return DeclarationContext::Interface; - case ParserState::TypeDefinitionFinishAsNamedConstraint: - return DeclarationContext::NamedConstraint; - default: - llvm_unreachable("Missing handling for a declaration scope"); - } - } - } - CARBON_CHECK(!state_stack_.empty() && - state_stack_[0].state == ParserState::DeclarationScopeLoop); - return DeclarationContext::File; -} - -auto Parser::HandleDeclarationError(StateStackEntry state, - ParseNodeKind parse_node_kind, - bool skip_past_likely_end) -> void { - auto token = state.token; - if (skip_past_likely_end) { - if (auto semi = SkipPastLikelyEnd(token)) { - token = *semi; - } - } - AddNode(parse_node_kind, token, state.subtree_start, - /*has_error=*/true); -} - -auto Parser::HandleUnrecognizedDeclaration() -> void { - CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error, - "Unrecognized declaration introducer."); - emitter_->Emit(*position_, UnrecognizedDeclaration); - auto cursor = *position_; - auto semi = SkipPastLikelyEnd(cursor); - // Locate the EmptyDeclaration at the semi when found, but use the - // original cursor location for an error when not. - AddLeafNode(ParseNodeKind::EmptyDeclaration, semi ? *semi : cursor, - /*has_error=*/true); -} - -auto Parser::HandleBraceExpressionState() -> void { - auto state = PopState(); - - state.state = ParserState::BraceExpressionFinishAsUnknown; - PushState(state); - - CARBON_CHECK(ConsumeAndAddLeafNodeIf( - TokenKind::OpenCurlyBrace, - ParseNodeKind::StructLiteralOrStructTypeLiteralStart)); - if (!PositionIs(TokenKind::CloseCurlyBrace)) { - PushState(ParserState::BraceExpressionParameterAsUnknown); - } -} - -auto Parser::HandleBraceExpressionParameterError(StateStackEntry state, - ParserState param_finish_state) - -> void { - bool is_type = - param_finish_state == ParserState::BraceExpressionParameterFinishAsType; - bool is_value = - param_finish_state == ParserState::BraceExpressionParameterFinishAsValue; - bool is_unknown = param_finish_state == - ParserState::BraceExpressionParameterFinishAsUnknown; - CARBON_CHECK(is_type || is_value || is_unknown); - CARBON_DIAGNOSTIC(ExpectedStructLiteralField, Error, "Expected {0}{1}{2}.", - llvm::StringRef, llvm::StringRef, llvm::StringRef); - emitter_->Emit(*position_, ExpectedStructLiteralField, - (is_type || is_unknown) ? "`.field: field_type`" : "", - is_unknown ? " or " : "", - (is_value || is_unknown) ? "`.field = value`" : ""); - - state.state = param_finish_state; - state.has_error = true; - PushState(state); -} - -auto Parser::HandleBraceExpressionParameter(ParserState after_designator_state, - ParserState param_finish_state) - -> void { - auto state = PopState(); - - if (!PositionIs(TokenKind::Period)) { - HandleBraceExpressionParameterError(state, param_finish_state); - return; - } - - state.state = after_designator_state; - PushState(state); - PushState(ParserState::DesignatorAsStruct); -} - -auto Parser::HandleBraceExpressionParameterAsTypeState() -> void { - HandleBraceExpressionParameter( - ParserState::BraceExpressionParameterAfterDesignatorAsType, - ParserState::BraceExpressionParameterFinishAsType); -} - -auto Parser::HandleBraceExpressionParameterAsValueState() -> void { - HandleBraceExpressionParameter( - ParserState::BraceExpressionParameterAfterDesignatorAsValue, - ParserState::BraceExpressionParameterFinishAsValue); -} - -auto Parser::HandleBraceExpressionParameterAsUnknownState() -> void { - HandleBraceExpressionParameter( - ParserState::BraceExpressionParameterAfterDesignatorAsUnknown, - ParserState::BraceExpressionParameterFinishAsUnknown); -} - -auto Parser::HandleBraceExpressionParameterAfterDesignator( - ParserState param_finish_state) -> void { - auto state = PopState(); - - if (state.has_error) { - auto recovery_pos = - FindNextOf({TokenKind::Equal, TokenKind::Colon, TokenKind::Comma}); - if (!recovery_pos || tokens_->GetKind(*recovery_pos) == TokenKind::Comma) { - state.state = param_finish_state; - PushState(state); - return; - } - SkipTo(*recovery_pos); - } - - // Work out the kind of this element. - bool is_type; - if (PositionIs(TokenKind::Colon)) { - is_type = true; - } else if (PositionIs(TokenKind::Equal)) { - is_type = false; - } else { - HandleBraceExpressionParameterError(state, param_finish_state); - return; - } - - // If we're changing from unknown, update the related finish states. - if (param_finish_state == - ParserState::BraceExpressionParameterFinishAsUnknown) { - auto finish_state = PopState(); - CARBON_CHECK(finish_state.state == - ParserState::BraceExpressionFinishAsUnknown); - if (is_type) { - finish_state.state = ParserState::BraceExpressionFinishAsType; - param_finish_state = ParserState::BraceExpressionParameterFinishAsType; - } else { - finish_state.state = ParserState::BraceExpressionFinishAsValue; - param_finish_state = ParserState::BraceExpressionParameterFinishAsValue; - } - PushState(finish_state); - } - - auto want_param_finish_state = - is_type ? ParserState::BraceExpressionParameterFinishAsType - : ParserState::BraceExpressionParameterFinishAsValue; - if (param_finish_state != want_param_finish_state) { - HandleBraceExpressionParameterError(state, param_finish_state); - return; - } - - // Struct type fields and value fields use the same grammar except - // that one has a `:` separator and the other has an `=` separator. - state.state = param_finish_state; - state.token = Consume(); - PushState(state); - PushState(ParserState::Expression); -} - -auto Parser::HandleBraceExpressionParameterAfterDesignatorAsTypeState() - -> void { - HandleBraceExpressionParameterAfterDesignator( - ParserState::BraceExpressionParameterFinishAsType); -} - -auto Parser::HandleBraceExpressionParameterAfterDesignatorAsValueState() - -> void { - HandleBraceExpressionParameterAfterDesignator( - ParserState::BraceExpressionParameterFinishAsValue); -} - -auto Parser::HandleBraceExpressionParameterAfterDesignatorAsUnknownState() - -> void { - HandleBraceExpressionParameterAfterDesignator( - ParserState::BraceExpressionParameterFinishAsUnknown); -} - -auto Parser::HandleBraceExpressionParameterFinish(ParseNodeKind node_kind, - ParserState param_state) - -> void { - auto state = PopState(); - - if (state.has_error) { - AddLeafNode(ParseNodeKind::StructFieldUnknown, state.token, - /*has_error=*/true); - } else { - AddNode(node_kind, state.token, state.subtree_start, /*has_error=*/false); - } - - if (ConsumeListToken(ParseNodeKind::StructComma, TokenKind::CloseCurlyBrace, - state.has_error) == ListTokenKind::Comma) { - PushState(param_state); - } -} - -auto Parser::HandleBraceExpressionParameterFinishAsTypeState() -> void { - HandleBraceExpressionParameterFinish( - ParseNodeKind::StructFieldType, - ParserState::BraceExpressionParameterAsType); -} - -auto Parser::HandleBraceExpressionParameterFinishAsValueState() -> void { - HandleBraceExpressionParameterFinish( - ParseNodeKind::StructFieldValue, - ParserState::BraceExpressionParameterAsValue); -} - -auto Parser::HandleBraceExpressionParameterFinishAsUnknownState() -> void { - HandleBraceExpressionParameterFinish( - ParseNodeKind::StructFieldUnknown, - ParserState::BraceExpressionParameterAsUnknown); -} - -auto Parser::HandleBraceExpressionFinish(ParseNodeKind node_kind) -> void { - auto state = PopState(); - - AddNode(node_kind, Consume(), state.subtree_start, state.has_error); -} - -auto Parser::HandleBraceExpressionFinishAsTypeState() -> void { - HandleBraceExpressionFinish(ParseNodeKind::StructTypeLiteral); -} - -auto Parser::HandleBraceExpressionFinishAsValueState() -> void { - HandleBraceExpressionFinish(ParseNodeKind::StructLiteral); -} - -auto Parser::HandleBraceExpressionFinishAsUnknownState() -> void { - HandleBraceExpressionFinish(ParseNodeKind::StructLiteral); -} - -auto Parser::HandleCallExpressionState() -> void { - auto state = PopState(); - - state.state = ParserState::CallExpressionFinish; - PushState(state); - - AddNode(ParseNodeKind::CallExpressionStart, Consume(), state.subtree_start, - state.has_error); - if (!PositionIs(TokenKind::CloseParen)) { - PushState(ParserState::CallExpressionParameterFinish); - PushState(ParserState::Expression); - } -} - -auto Parser::HandleCallExpressionParameterFinishState() -> void { - auto state = PopState(); - - if (state.has_error) { - ReturnErrorOnState(); - } - - if (ConsumeListToken(ParseNodeKind::CallExpressionComma, - TokenKind::CloseParen, - state.has_error) == ListTokenKind::Comma) { - PushState(ParserState::CallExpressionParameterFinish); - PushState(ParserState::Expression); - } -} - -auto Parser::HandleCallExpressionFinishState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::CallExpression, Consume(), state.subtree_start, - state.has_error); -} - -auto Parser::HandleCodeBlockFinishState() -> void { - auto state = PopState(); - - // If the block started with an open curly, this is a close curly. - if (tokens_->GetKind(state.token) == TokenKind::OpenCurlyBrace) { - AddNode(ParseNodeKind::CodeBlock, Consume(), state.subtree_start, - state.has_error); - } else { - AddNode(ParseNodeKind::CodeBlock, state.token, state.subtree_start, - /*has_error=*/true); - } -} - -auto Parser::HandleDeclarationNameAndParams(bool params_required) -> void { - auto state = PopState(); - - if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier, - ParseNodeKind::DeclaredName)) { - emitter_->Emit(*position_, ExpectedDeclarationName, - tokens_->GetKind(state.token)); - ReturnErrorOnState(); - return; - } - - if (PositionIs(TokenKind::OpenSquareBracket)) { - PushState(ParserState::DeclarationNameAndParamsAfterDeduced); - PushState(ParserState::ParameterListAsDeduced); - } else if (PositionIs(TokenKind::OpenParen)) { - PushState(ParserState::ParameterListAsRegular); - } else if (params_required) { - CARBON_DIAGNOSTIC(ParametersRequiredByIntroducer, Error, - "`{0}` requires a `(` for parameters.", TokenKind); - emitter_->Emit(*position_, ParametersRequiredByIntroducer, - tokens_->GetKind(state.token)); - ReturnErrorOnState(); - } -} - -auto Parser::HandleDeclarationNameAndParamsAsOptionalState() -> void { - HandleDeclarationNameAndParams(/*params_required=*/false); -} - -auto Parser::HandleDeclarationNameAndParamsAsRequiredState() -> void { - HandleDeclarationNameAndParams(/*params_required=*/true); -} - -auto Parser::HandleDeclarationNameAndParamsAfterDeducedState() -> void { - PopAndDiscardState(); - - if (PositionIs(TokenKind::OpenParen)) { - PushState(ParserState::ParameterListAsRegular); - } else { - CARBON_DIAGNOSTIC( - ParametersRequiredByDeduced, Error, - "A `(` for parameters is required after deduced parameters."); - emitter_->Emit(*position_, ParametersRequiredByDeduced); - ReturnErrorOnState(); - } -} - -auto Parser::HandleDeclarationScopeLoopState() -> void { - // This maintains the current state unless we're at the end of the scope. - - switch (PositionKind()) { - case TokenKind::CloseCurlyBrace: - case TokenKind::EndOfFile: { - // This is the end of the scope, so the loop state ends. - PopAndDiscardState(); - break; - } - case TokenKind::Class: { - PushState(ParserState::TypeIntroducerAsClass); - break; - } - case TokenKind::Constraint: { - PushState(ParserState::TypeIntroducerAsNamedConstraint); - break; - } - case TokenKind::Fn: { - PushState(ParserState::FunctionIntroducer); - break; - } - case TokenKind::Interface: { - PushState(ParserState::TypeIntroducerAsInterface); - break; - } - case TokenKind::Semi: { - AddLeafNode(ParseNodeKind::EmptyDeclaration, Consume()); - break; - } - case TokenKind::Var: { - PushState(ParserState::VarAsSemicolon); - break; - } - default: { - HandleUnrecognizedDeclaration(); - break; - } - } -} - -auto Parser::HandleDesignator(bool as_struct) -> void { - auto state = PopState(); - - // `.` identifier - auto dot = ConsumeChecked(TokenKind::Period); - - if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier, - ParseNodeKind::DesignatedName)) { - CARBON_DIAGNOSTIC(ExpectedIdentifierAfterDot, Error, - "Expected identifier after `.`."); - emitter_->Emit(*position_, ExpectedIdentifierAfterDot); - // If we see a keyword, assume it was intended to be the designated name. - // TODO: Should keywords be valid in designators? - if (PositionKind().is_keyword()) { - AddLeafNode(ParseNodeKind::DesignatedName, Consume(), - /*has_error=*/true); - } else { - AddLeafNode(ParseNodeKind::DesignatedName, *position_, - /*has_error=*/true); - // Indicate the error to the parent state so that it can avoid producing - // more errors. - ReturnErrorOnState(); - } - } - - AddNode(as_struct ? ParseNodeKind::StructFieldDesignator - : ParseNodeKind::DesignatorExpression, - dot, state.subtree_start, state.has_error); -} - -auto Parser::HandleDesignatorAsExpressionState() -> void { - HandleDesignator(/*as_struct=*/false); -} - -auto Parser::HandleDesignatorAsStructState() -> void { - HandleDesignator(/*as_struct=*/true); -} - -auto Parser::HandleExpressionState() -> void { - auto state = PopState(); - - // Check for a prefix operator. - if (auto operator_precedence = PrecedenceGroup::ForLeading(PositionKind())) { - if (PrecedenceGroup::GetPriority(state.ambient_precedence, - *operator_precedence) != - OperatorPriority::RightFirst) { - // The precedence rules don't permit this prefix operator in this - // context. Diagnose this, but carry on and parse it anyway. - emitter_->Emit(*position_, OperatorRequiresParentheses); - } else { - // Check that this operator follows the proper whitespace rules. - DiagnoseOperatorFixity(OperatorFixity::Prefix); - } - - PushStateForExpressionLoop(ParserState::ExpressionLoopForPrefix, - state.ambient_precedence, *operator_precedence); - ++position_; - PushStateForExpression(*operator_precedence); - } else { - PushStateForExpressionLoop(ParserState::ExpressionLoop, - state.ambient_precedence, - PrecedenceGroup::ForPostfixExpression()); - PushState(ParserState::ExpressionInPostfix); - } -} - -auto Parser::HandleExpressionInPostfixState() -> void { - auto state = PopState(); - - // Continue to the loop state. - state.state = ParserState::ExpressionInPostfixLoop; - - // Parses a primary expression, which is either a terminal portion of an - // expression tree, such as an identifier or literal, or a parenthesized - // expression. - switch (PositionKind()) { - case TokenKind::Identifier: { - AddLeafNode(ParseNodeKind::NameReference, Consume()); - PushState(state); - break; - } - case TokenKind::IntegerLiteral: - case TokenKind::RealLiteral: - case TokenKind::StringLiteral: - case TokenKind::IntegerTypeLiteral: - case TokenKind::UnsignedIntegerTypeLiteral: - case TokenKind::FloatingPointTypeLiteral: - case TokenKind::StringTypeLiteral: { - AddLeafNode(ParseNodeKind::Literal, Consume()); - PushState(state); - break; - } - case TokenKind::OpenCurlyBrace: { - PushState(state); - PushState(ParserState::BraceExpression); - break; - } - case TokenKind::OpenParen: { - PushState(state); - PushState(ParserState::ParenExpression); - break; - } - case TokenKind::SelfValueIdentifier: { - AddLeafNode(ParseNodeKind::SelfValueIdentifier, Consume()); - PushState(state); - break; - } - case TokenKind::SelfTypeIdentifier: { - AddLeafNode(ParseNodeKind::SelfTypeIdentifier, Consume()); - PushState(state); - break; - } - default: { - // Add a node to keep the parse tree balanced. - AddLeafNode(ParseNodeKind::InvalidParse, *position_, /*has_error=*/true); - CARBON_DIAGNOSTIC(ExpectedExpression, Error, "Expected expression."); - emitter_->Emit(*position_, ExpectedExpression); - ReturnErrorOnState(); - break; - } - } -} - -auto Parser::HandleExpressionInPostfixLoopState() -> void { - // This is a cyclic state that repeats, so this state is typically pushed back - // on. - auto state = PopState(); - - state.token = *position_; - - switch (PositionKind()) { - case TokenKind::Period: { - PushState(state); - state.state = ParserState::DesignatorAsExpression; - PushState(state); - break; - } - case TokenKind::OpenParen: { - PushState(state); - state.state = ParserState::CallExpression; - PushState(state); - break; - } - default: { - if (state.has_error) { - ReturnErrorOnState(); - } - break; - } - } -} - -auto Parser::HandleExpressionLoopState() -> void { - auto state = PopState(); - - auto trailing_operator = - PrecedenceGroup::ForTrailing(PositionKind(), IsTrailingOperatorInfix()); - if (!trailing_operator) { - if (state.has_error) { - ReturnErrorOnState(); - } - return; - } - auto [operator_precedence, is_binary] = *trailing_operator; - - // TODO: If this operator is ambiguous with either the ambient precedence - // or the LHS precedence, and there's a variant with a different fixity - // that would work, use that one instead for error recovery. - if (PrecedenceGroup::GetPriority(state.ambient_precedence, - operator_precedence) != - OperatorPriority::RightFirst) { - // The precedence rules don't permit this operator in this context. Try - // again in the enclosing expression context. - if (state.has_error) { - ReturnErrorOnState(); - } - return; - } - - if (PrecedenceGroup::GetPriority(state.lhs_precedence, operator_precedence) != - OperatorPriority::LeftFirst) { - // Either the LHS operator and this operator are ambiguous, or the - // LHS operator is a unary operator that can't be nested within - // this operator. Either way, parentheses are required. - emitter_->Emit(*position_, OperatorRequiresParentheses); - state.has_error = true; - } else { - DiagnoseOperatorFixity(is_binary ? OperatorFixity::Infix - : OperatorFixity::Postfix); - } - - state.token = Consume(); - state.lhs_precedence = operator_precedence; - - if (is_binary) { - state.state = ParserState::ExpressionLoopForBinary; - PushState(state); - PushStateForExpression(operator_precedence); - } else { - AddNode(ParseNodeKind::PostfixOperator, state.token, state.subtree_start, - state.has_error); - state.has_error = false; - PushState(state); - } -} - -auto Parser::HandleExpressionLoopForBinaryState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::InfixOperator, state.token, state.subtree_start, - state.has_error); - state.state = ParserState::ExpressionLoop; - state.has_error = false; - PushState(state); -} - -auto Parser::HandleExpressionLoopForPrefixState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::PrefixOperator, state.token, state.subtree_start, - state.has_error); - state.state = ParserState::ExpressionLoop; - state.has_error = false; - PushState(state); -} - -auto Parser::HandleExpressionStatementFinishState() -> void { - auto state = PopState(); - - if (auto semi = ConsumeIf(TokenKind::Semi)) { - AddNode(ParseNodeKind::ExpressionStatement, *semi, state.subtree_start, - state.has_error); - return; - } - - if (!state.has_error) { - emitter_->Emit(*position_, ExpectedSemiAfterExpression); - } - - if (auto semi_token = SkipPastLikelyEnd(state.token)) { - AddNode(ParseNodeKind::ExpressionStatement, *semi_token, - state.subtree_start, - /*has_error=*/true); - return; - } - - // Found junk not even followed by a `;`, no node to add. - ReturnErrorOnState(); -} - -auto Parser::HandleFunctionIntroducerState() -> void { - auto state = PopState(); - - AddLeafNode(ParseNodeKind::FunctionIntroducer, Consume()); - - state.state = ParserState::FunctionAfterParameters; - PushState(state); - state.state = ParserState::DeclarationNameAndParamsAsRequired; - PushState(state); -} - -auto Parser::HandleFunctionAfterParametersState() -> void { - auto state = PopState(); - - // Regardless of whether there's a return type, we'll finish the signature. - state.state = ParserState::FunctionSignatureFinish; - PushState(state); - - // If there is a return type, parse the expression before adding the return - // type nod.e - if (PositionIs(TokenKind::MinusGreater)) { - PushState(ParserState::FunctionReturnTypeFinish); - ++position_; - PushStateForExpression(PrecedenceGroup::ForType()); - } -} - -auto Parser::HandleFunctionReturnTypeFinishState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::ReturnType, state.token, state.subtree_start, - state.has_error); -} - -auto Parser::HandleFunctionSignatureFinishState() -> void { - auto state = PopState(); - - switch (PositionKind()) { - case TokenKind::Semi: { - AddNode(ParseNodeKind::FunctionDeclaration, Consume(), - state.subtree_start, state.has_error); - break; - } - case TokenKind::OpenCurlyBrace: { - if (auto context = GetDeclarationContext(); - context == DeclarationContext::Interface || - context == DeclarationContext::NamedConstraint) { - CARBON_DIAGNOSTIC( - MethodImplNotAllowed, Error, - "Method implementations are not allowed in interfaces."); - emitter_->Emit(*position_, MethodImplNotAllowed); - HandleDeclarationError(state, ParseNodeKind::FunctionDeclaration, - /*skip_past_likely_end=*/true); - break; - } - - AddNode(ParseNodeKind::FunctionDefinitionStart, Consume(), - state.subtree_start, state.has_error); - // Any error is recorded on the FunctionDefinitionStart. - state.has_error = false; - state.state = ParserState::FunctionDefinitionFinish; - PushState(state); - PushState(ParserState::StatementScopeLoop); - break; - } - default: { - if (!state.has_error) { - emitter_->Emit(*position_, ExpectedDeclarationSemiOrDefinition, - TokenKind::Fn); - } - // Only need to skip if we've not already found a new line. - bool skip_past_likely_end = - tokens_->GetLine(*position_) == tokens_->GetLine(state.token); - HandleDeclarationError(state, ParseNodeKind::FunctionDeclaration, - skip_past_likely_end); - break; - } - } -} - -auto Parser::HandleFunctionDefinitionFinishState() -> void { - auto state = PopState(); - AddNode(ParseNodeKind::FunctionDefinition, Consume(), state.subtree_start, - state.has_error); -} - -auto Parser::HandlePackageState() -> void { - auto state = PopState(); - - AddLeafNode(ParseNodeKind::PackageIntroducer, Consume()); - - auto exit_on_parse_error = [&]() { - auto semi_token = SkipPastLikelyEnd(state.token); - return AddNode(ParseNodeKind::PackageDirective, - semi_token ? *semi_token : state.token, state.subtree_start, - /*has_error=*/true); - }; - - if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier, - ParseNodeKind::DeclaredName)) { - CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPackage, Error, - "Expected identifier after `package`."); - emitter_->Emit(*position_, ExpectedIdentifierAfterPackage); - exit_on_parse_error(); - return; - } - - bool library_parsed = false; - if (auto library_token = ConsumeIf(TokenKind::Library)) { - auto library_start = tree_->size(); - - if (!ConsumeAndAddLeafNodeIf(TokenKind::StringLiteral, - ParseNodeKind::Literal)) { - CARBON_DIAGNOSTIC( - ExpectedLibraryName, Error, - "Expected a string literal to specify the library name."); - emitter_->Emit(*position_, ExpectedLibraryName); - exit_on_parse_error(); - return; - } - - AddNode(ParseNodeKind::PackageLibrary, *library_token, library_start, - /*has_error=*/false); - library_parsed = true; - } - - switch (auto api_or_impl_token = tokens_->GetKind(*(position_))) { - case TokenKind::Api: { - AddLeafNode(ParseNodeKind::PackageApi, Consume()); - break; - } - case TokenKind::Impl: { - AddLeafNode(ParseNodeKind::PackageImpl, Consume()); - break; - } - default: { - if (!library_parsed && api_or_impl_token == TokenKind::StringLiteral) { - // If we come acroess a string literal and we didn't parse `library - // "..."` yet, then most probably the user forgot to add `library` - // before the library name. - CARBON_DIAGNOSTIC(MissingLibraryKeyword, Error, - "Missing `library` keyword."); - emitter_->Emit(*position_, MissingLibraryKeyword); - } else { - CARBON_DIAGNOSTIC(ExpectedApiOrImpl, Error, - "Expected a `api` or `impl`."); - emitter_->Emit(*position_, ExpectedApiOrImpl); - } - exit_on_parse_error(); - return; - } - } - - if (!PositionIs(TokenKind::Semi)) { - CARBON_DIAGNOSTIC(ExpectedSemiToEndPackageDirective, Error, - "Expected `;` to end package directive."); - emitter_->Emit(*position_, ExpectedSemiToEndPackageDirective); - exit_on_parse_error(); - return; - } - - AddNode(ParseNodeKind::PackageDirective, Consume(), state.subtree_start, - /*has_error=*/false); -} - -auto Parser::HandleParameter(ParserState pattern_state, - ParserState finish_state) -> void { - PopAndDiscardState(); - - PushState(finish_state); - PushState(pattern_state); -} - -auto Parser::HandleParameterAsDeducedState() -> void { - HandleParameter(ParserState::PatternAsDeducedParameter, - ParserState::ParameterFinishAsDeduced); -} - -auto Parser::HandleParameterAsRegularState() -> void { - HandleParameter(ParserState::PatternAsParameter, - ParserState::ParameterFinishAsRegular); -} - -auto Parser::HandleParameterFinish(TokenKind close_token, - ParserState param_state) -> void { - auto state = PopState(); - - if (state.has_error) { - ReturnErrorOnState(); - } - - if (ConsumeListToken(ParseNodeKind::ParameterListComma, close_token, - state.has_error) == ListTokenKind::Comma) { - PushState(param_state); - } -} - -auto Parser::HandleParameterFinishAsDeducedState() -> void { - HandleParameterFinish(TokenKind::CloseSquareBracket, - ParserState::ParameterAsDeduced); -} - -auto Parser::HandleParameterFinishAsRegularState() -> void { - HandleParameterFinish(TokenKind::CloseParen, ParserState::ParameterAsRegular); -} - -auto Parser::HandleParameterList(ParseNodeKind parse_node_kind, - TokenKind open_token_kind, - TokenKind close_token_kind, - ParserState param_state, - ParserState finish_state) -> void { - PopAndDiscardState(); - - PushState(finish_state); - AddLeafNode(parse_node_kind, ConsumeChecked(open_token_kind)); - - if (!PositionIs(close_token_kind)) { - PushState(param_state); - } -} - -auto Parser::HandleParameterListAsDeducedState() -> void { - HandleParameterList( - ParseNodeKind::DeducedParameterListStart, TokenKind::OpenSquareBracket, - TokenKind::CloseSquareBracket, ParserState::ParameterAsDeduced, - ParserState::ParameterListFinishAsDeduced); -} - -auto Parser::HandleParameterListAsRegularState() -> void { - HandleParameterList(ParseNodeKind::ParameterListStart, TokenKind::OpenParen, - TokenKind::CloseParen, ParserState::ParameterAsRegular, - ParserState::ParameterListFinishAsRegular); -} - -auto Parser::HandleParameterListFinish(ParseNodeKind parse_node_kind, - TokenKind token_kind) -> void { - auto state = PopState(); - - AddNode(parse_node_kind, ConsumeChecked(token_kind), state.subtree_start, - state.has_error); -} - -auto Parser::HandleParameterListFinishAsDeducedState() -> void { - HandleParameterListFinish(ParseNodeKind::DeducedParameterList, - TokenKind::CloseSquareBracket); -} - -auto Parser::HandleParameterListFinishAsRegularState() -> void { - HandleParameterListFinish(ParseNodeKind::ParameterList, - TokenKind::CloseParen); -} - -auto Parser::HandleParenCondition(ParseNodeKind start_kind, - ParserState finish_state) -> void { - auto state = PopState(); - - ConsumeAndAddOpenParen(state.token, start_kind); - - state.state = finish_state; - PushState(state); - PushState(ParserState::Expression); -} - -auto Parser::HandleParenConditionAsIfState() -> void { - HandleParenCondition(ParseNodeKind::IfConditionStart, - ParserState::ParenConditionFinishAsIf); -} - -auto Parser::HandleParenConditionAsWhileState() -> void { - HandleParenCondition(ParseNodeKind::WhileConditionStart, - ParserState::ParenConditionFinishAsWhile); -} - -auto Parser::HandleParenConditionFinishAsIfState() -> void { - auto state = PopState(); - - ConsumeAndAddCloseParen(state, ParseNodeKind::IfCondition); -} - -auto Parser::HandleParenConditionFinishAsWhileState() -> void { - auto state = PopState(); - - ConsumeAndAddCloseParen(state, ParseNodeKind::WhileCondition); -} - -auto Parser::HandleParenExpressionState() -> void { - auto state = PopState(); - - // Advance past the open paren. - AddLeafNode(ParseNodeKind::ParenExpressionOrTupleLiteralStart, - ConsumeChecked(TokenKind::OpenParen)); - - if (PositionIs(TokenKind::CloseParen)) { - state.state = ParserState::ParenExpressionFinishAsTuple; - PushState(state); - } else { - state.state = ParserState::ParenExpressionFinishAsNormal; - PushState(state); - PushState(ParserState::ParenExpressionParameterFinishAsUnknown); - PushState(ParserState::Expression); - } -} - -auto Parser::HandleParenExpressionParameterFinish(bool as_tuple) -> void { - auto state = PopState(); - - auto list_token_kind = ConsumeListToken( - ParseNodeKind::TupleLiteralComma, TokenKind::CloseParen, state.has_error); - if (list_token_kind == ListTokenKind::Close) { - return; - } - - // If this is the first item and a comma was found, switch to tuple handling. - // Note this could be `(expr,)` so we may not reuse the current state, but - // it's still necessary to switch the parent. - if (!as_tuple) { - state.state = ParserState::ParenExpressionParameterFinishAsTuple; - - auto finish_state = PopState(); - CARBON_CHECK(finish_state.state == - ParserState::ParenExpressionFinishAsNormal) - << "Unexpected parent state, found: " << finish_state.state; - finish_state.state = ParserState::ParenExpressionFinishAsTuple; - PushState(finish_state); - } - - // On a comma, push another expression handler. - if (list_token_kind == ListTokenKind::Comma) { - PushState(state); - PushState(ParserState::Expression); - } -} - -auto Parser::HandleParenExpressionParameterFinishAsUnknownState() -> void { - HandleParenExpressionParameterFinish(/*as_tuple=*/false); -} - -auto Parser::HandleParenExpressionParameterFinishAsTupleState() -> void { - HandleParenExpressionParameterFinish(/*as_tuple=*/true); -} - -auto Parser::HandleParenExpressionFinishAsNormalState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::ParenExpression, Consume(), state.subtree_start, - state.has_error); -} - -auto Parser::HandleParenExpressionFinishAsTupleState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::TupleLiteral, Consume(), state.subtree_start, - state.has_error); -} - -auto Parser::ConsumeIfPatternKeyword(TokenKind keyword_token, - ParserState keyword_state, - int subtree_start) -> void { - if (auto token = ConsumeIf(keyword_token)) { - PushState(StateStackEntry( - keyword_state, PrecedenceGroup::ForTopLevelExpression(), - PrecedenceGroup::ForTopLevelExpression(), *token, subtree_start)); - } -} - -auto Parser::HandlePattern(PatternKind pattern_kind) -> void { - auto state = PopState(); - - // Parameters may have keywords prefixing the pattern. They become the parent - // for the full PatternBinding. - if (pattern_kind != PatternKind::Variable) { - ConsumeIfPatternKeyword(TokenKind::Template, ParserState::PatternTemplate, - state.subtree_start); - ConsumeIfPatternKeyword(TokenKind::Addr, ParserState::PatternAddress, - state.subtree_start); - } - - // Handle an invalid pattern introducer for parameters and variables. - auto on_error = [&]() { - switch (pattern_kind) { - case PatternKind::DeducedParameter: - case PatternKind::Parameter: { - CARBON_DIAGNOSTIC(ExpectedParameterName, Error, - "Expected parameter declaration."); - emitter_->Emit(*position_, ExpectedParameterName); - break; - } - case PatternKind::Variable: { - CARBON_DIAGNOSTIC(ExpectedVariableName, Error, - "Expected pattern in `var` declaration."); - emitter_->Emit(*position_, ExpectedVariableName); - break; - } - } - // Add a placeholder for the type. - AddLeafNode(ParseNodeKind::InvalidParse, *position_, /*has_error=*/true); - state.state = ParserState::PatternFinishAsRegular; - state.has_error = true; - PushState(state); - }; - - // The first item should be an identifier or, for deduced parameters, `self`. - bool has_name = false; - if (auto identifier = ConsumeIf(TokenKind::Identifier)) { - AddLeafNode(ParseNodeKind::DeclaredName, *identifier); - has_name = true; - } else if (pattern_kind == PatternKind::DeducedParameter) { - if (auto self = ConsumeIf(TokenKind::SelfValueIdentifier)) { - AddLeafNode(ParseNodeKind::SelfValueIdentifier, *self); - has_name = true; - } - } - if (!has_name) { - // Add a placeholder for the name. - AddLeafNode(ParseNodeKind::DeclaredName, *position_, /*has_error=*/true); - on_error(); - return; - } - - if (auto kind = PositionKind(); - kind == TokenKind::Colon || kind == TokenKind::ColonExclaim) { - state.state = kind == TokenKind::Colon - ? ParserState::PatternFinishAsRegular - : ParserState::PatternFinishAsGeneric; - // Use the `:` or `:!` for the root node. - state.token = Consume(); - PushState(state); - PushStateForExpression(PrecedenceGroup::ForType()); - } else { - on_error(); - return; - } -} - -auto Parser::HandlePatternAsDeducedParameterState() -> void { - HandlePattern(PatternKind::DeducedParameter); -} - -auto Parser::HandlePatternAsParameterState() -> void { - HandlePattern(PatternKind::Parameter); -} - -auto Parser::HandlePatternAsVariableState() -> void { - HandlePattern(PatternKind::Variable); -} - -auto Parser::HandlePatternFinish(ParseNodeKind node_kind) -> void { - auto state = PopState(); - - AddNode(node_kind, state.token, state.subtree_start, state.has_error); - - // Propagate errors to the parent state so that they can take different - // actions on invalid patterns. - if (state.has_error) { - ReturnErrorOnState(); - } -} - -auto Parser::HandlePatternFinishAsGenericState() -> void { - HandlePatternFinish(ParseNodeKind::GenericPatternBinding); -} - -auto Parser::HandlePatternFinishAsRegularState() -> void { - HandlePatternFinish(ParseNodeKind::PatternBinding); -} - -auto Parser::HandlePatternAddressState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::Address, state.token, state.subtree_start, - state.has_error); - - // If an error was encountered, propagate it while adding a node. - if (state.has_error) { - ReturnErrorOnState(); - } -} - -auto Parser::HandlePatternTemplateState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::Template, state.token, state.subtree_start, - state.has_error); - - // If an error was encountered, propagate it while adding a node. - if (state.has_error) { - ReturnErrorOnState(); - } -} - -auto Parser::HandleStatementState() -> void { - PopAndDiscardState(); - - switch (PositionKind()) { - case TokenKind::Break: { - PushState(ParserState::StatementBreakFinish); - AddLeafNode(ParseNodeKind::BreakStatementStart, Consume()); - break; - } - case TokenKind::Continue: { - PushState(ParserState::StatementContinueFinish); - AddLeafNode(ParseNodeKind::ContinueStatementStart, Consume()); - break; - } - case TokenKind::For: { - PushState(ParserState::StatementForFinish); - PushState(ParserState::StatementForHeader); - ++position_; - break; - } - case TokenKind::If: { - PushState(ParserState::StatementIf); - break; - } - case TokenKind::Return: { - PushState(ParserState::StatementReturn); - break; - } - case TokenKind::Var: { - PushState(ParserState::VarAsSemicolon); - break; - } - case TokenKind::While: { - PushState(ParserState::StatementWhile); - break; - } - default: { - PushState(ParserState::ExpressionStatementFinish); - PushState(ParserState::Expression); - break; - } - } -} - -auto Parser::HandleStatementBreakFinishState() -> void { - HandleStatementKeywordFinish(ParseNodeKind::BreakStatement); -} - -auto Parser::HandleStatementContinueFinishState() -> void { - HandleStatementKeywordFinish(ParseNodeKind::ContinueStatement); -} - -auto Parser::HandleStatementForHeaderState() -> void { - auto state = PopState(); - - ConsumeAndAddOpenParen(state.token, ParseNodeKind::ForHeaderStart); - - state.state = ParserState::StatementForHeaderIn; - - if (PositionIs(TokenKind::Var)) { - PushState(state); - PushState(ParserState::VarAsFor); - } else { - CARBON_DIAGNOSTIC(ExpectedVariableDeclaration, Error, - "Expected `var` declaration."); - emitter_->Emit(*position_, ExpectedVariableDeclaration); - - if (auto next_in = FindNextOf({TokenKind::In})) { - SkipTo(*next_in); - ++position_; - } - state.has_error = true; - PushState(state); - } -} - -auto Parser::HandleStatementForHeaderInState() -> void { - auto state = PopState(); - - state.state = ParserState::StatementForHeaderFinish; - PushState(state); - PushState(ParserState::Expression); -} - -auto Parser::HandleStatementForHeaderFinishState() -> void { - auto state = PopState(); - - ConsumeAndAddCloseParen(state, ParseNodeKind::ForHeader); - - PushState(ParserState::CodeBlock); -} - -auto Parser::HandleStatementForFinishState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::ForStatement, state.token, state.subtree_start, - state.has_error); -} - -auto Parser::HandleStatementIfState() -> void { - PopAndDiscardState(); - - PushState(ParserState::StatementIfConditionFinish); - PushState(ParserState::ParenConditionAsIf); - ++position_; -} - -auto Parser::HandleStatementIfConditionFinishState() -> void { - auto state = PopState(); - - state.state = ParserState::StatementIfThenBlockFinish; - PushState(state); - PushState(ParserState::CodeBlock); -} - -auto Parser::HandleStatementIfThenBlockFinishState() -> void { - auto state = PopState(); - - if (ConsumeAndAddLeafNodeIf(TokenKind::Else, - ParseNodeKind::IfStatementElse)) { - state.state = ParserState::StatementIfElseBlockFinish; - PushState(state); - // `else if` is permitted as a special case. - PushState(PositionIs(TokenKind::If) ? ParserState::StatementIf - : ParserState::CodeBlock); - } else { - AddNode(ParseNodeKind::IfStatement, state.token, state.subtree_start, - state.has_error); - } -} - -auto Parser::HandleStatementIfElseBlockFinishState() -> void { - auto state = PopState(); - AddNode(ParseNodeKind::IfStatement, state.token, state.subtree_start, - state.has_error); -} - -auto Parser::HandleStatementKeywordFinish(ParseNodeKind node_kind) -> void { - auto state = PopState(); - - auto semi = ConsumeIf(TokenKind::Semi); - if (!semi) { - CARBON_DIAGNOSTIC(ExpectedSemiAfter, Error, "Expected `;` after `{0}`.", - TokenKind); - emitter_->Emit(*position_, ExpectedSemiAfter, - tokens_->GetKind(state.token)); - state.has_error = true; - // Recover to the next semicolon if possible, otherwise indicate the - // keyword for the error. - semi = SkipPastLikelyEnd(state.token); - if (!semi) { - semi = state.token; - } - } - AddNode(node_kind, *semi, state.subtree_start, state.has_error); -} - -auto Parser::HandleStatementReturnState() -> void { - auto state = PopState(); - state.state = ParserState::StatementReturnFinish; - PushState(state); - - AddLeafNode(ParseNodeKind::ReturnStatementStart, Consume()); - if (!PositionIs(TokenKind::Semi)) { - PushState(ParserState::Expression); - } -} - -auto Parser::HandleStatementReturnFinishState() -> void { - HandleStatementKeywordFinish(ParseNodeKind::ReturnStatement); -} - -auto Parser::HandleStatementScopeLoopState() -> void { - // This maintains the current state until we're at the end of the scope. - - auto token_kind = PositionKind(); - if (token_kind == TokenKind::CloseCurlyBrace) { - auto state = PopState(); - if (state.has_error) { - ReturnErrorOnState(); - } - } else { - PushState(ParserState::Statement); - } -} - -auto Parser::HandleStatementWhileState() -> void { - PopAndDiscardState(); - - PushState(ParserState::StatementWhileConditionFinish); - PushState(ParserState::ParenConditionAsWhile); - ++position_; -} - -auto Parser::HandleStatementWhileConditionFinishState() -> void { - auto state = PopState(); - - state.state = ParserState::StatementWhileBlockFinish; - PushState(state); - PushState(ParserState::CodeBlock); -} - -auto Parser::HandleStatementWhileBlockFinishState() -> void { - auto state = PopState(); - - AddNode(ParseNodeKind::WhileStatement, state.token, state.subtree_start, - state.has_error); -} - -auto Parser::HandleTypeIntroducer(ParseNodeKind introducer_kind, - ParserState after_params_state) -> void { - auto state = PopState(); - - AddLeafNode(introducer_kind, Consume()); - - state.state = after_params_state; - PushState(state); - state.state = ParserState::DeclarationNameAndParamsAsOptional; - PushState(state); -} - -auto Parser::HandleTypeIntroducerAsClassState() -> void { - HandleTypeIntroducer(ParseNodeKind::ClassIntroducer, - ParserState::TypeAfterParamsAsClass); -} - -auto Parser::HandleTypeIntroducerAsInterfaceState() -> void { - HandleTypeIntroducer(ParseNodeKind::InterfaceIntroducer, - ParserState::TypeAfterParamsAsInterface); -} - -auto Parser::HandleTypeIntroducerAsNamedConstraintState() -> void { - HandleTypeIntroducer(ParseNodeKind::NamedConstraintIntroducer, - ParserState::TypeAfterParamsAsNamedConstraint); -} - -auto Parser::HandleTypeAfterParams(ParseNodeKind declaration_kind, - ParseNodeKind definition_start_kind, - ParserState definition_finish_state) - -> void { - auto state = PopState(); - - if (state.has_error) { - HandleDeclarationError(state, declaration_kind, - /*skip_past_likely_end=*/true); - return; - } - - if (auto semi = ConsumeIf(TokenKind::Semi)) { - AddNode(declaration_kind, *semi, state.subtree_start, state.has_error); - return; - } - - if (!PositionIs(TokenKind::OpenCurlyBrace)) { - emitter_->Emit(*position_, ExpectedDeclarationSemiOrDefinition, - tokens_->GetKind(state.token)); - HandleDeclarationError(state, declaration_kind, - /*skip_past_likely_end=*/true); - return; - } - - state.state = definition_finish_state; - PushState(state); - PushState(ParserState::DeclarationScopeLoop); - AddNode(definition_start_kind, Consume(), state.subtree_start, - state.has_error); -} - -auto Parser::HandleTypeAfterParamsAsClassState() -> void { - HandleTypeAfterParams(ParseNodeKind::ClassDeclaration, - ParseNodeKind::ClassDefinitionStart, - ParserState::TypeDefinitionFinishAsClass); -} - -auto Parser::HandleTypeAfterParamsAsInterfaceState() -> void { - HandleTypeAfterParams(ParseNodeKind::InterfaceDeclaration, - ParseNodeKind::InterfaceDefinitionStart, - ParserState::TypeDefinitionFinishAsInterface); -} - -auto Parser::HandleTypeAfterParamsAsNamedConstraintState() -> void { - HandleTypeAfterParams(ParseNodeKind::NamedConstraintDeclaration, - ParseNodeKind::NamedConstraintDefinitionStart, - ParserState::TypeDefinitionFinishAsNamedConstraint); -} - -auto Parser::HandleTypeDefinitionFinish(ParseNodeKind definition_kind) -> void { - auto state = PopState(); - - AddNode(definition_kind, Consume(), state.subtree_start, state.has_error); -} - -auto Parser::HandleTypeDefinitionFinishAsClassState() -> void { - HandleTypeDefinitionFinish(ParseNodeKind::ClassDefinition); -} - -auto Parser::HandleTypeDefinitionFinishAsInterfaceState() -> void { - HandleTypeDefinitionFinish(ParseNodeKind::InterfaceDefinition); -} - -auto Parser::HandleTypeDefinitionFinishAsNamedConstraintState() -> void { - HandleTypeDefinitionFinish(ParseNodeKind::NamedConstraintDefinition); -} - -auto Parser::HandleVar(ParserState finish_state) -> void { - PopAndDiscardState(); - - // These will start at the `var`. - PushState(finish_state); - PushState(ParserState::VarAfterPattern); - - AddLeafNode(ParseNodeKind::VariableIntroducer, Consume()); - - // This will start at the pattern. - PushState(ParserState::PatternAsVariable); -} - -auto Parser::HandleVarAsSemicolonState() -> void { - HandleVar(ParserState::VarFinishAsSemicolon); -} - -auto Parser::HandleVarAsForState() -> void { - HandleVar(ParserState::VarFinishAsFor); -} - -auto Parser::HandleVarAfterPatternState() -> void { - auto state = PopState(); - - if (state.has_error) { - if (auto after_pattern = FindNextOf({TokenKind::Equal, TokenKind::Semi})) { - SkipTo(*after_pattern); - } - } - - if (auto equals = ConsumeIf(TokenKind::Equal)) { - AddLeafNode(ParseNodeKind::VariableInitializer, *equals); - PushState(ParserState::Expression); - } -} - -auto Parser::HandleVarFinishAsSemicolonState() -> void { - auto state = PopState(); - - auto end_token = state.token; - if (PositionIs(TokenKind::Semi)) { - end_token = Consume(); - } else { - emitter_->Emit(*position_, ExpectedSemiAfterExpression); - state.has_error = true; - if (auto semi_token = SkipPastLikelyEnd(state.token)) { - end_token = *semi_token; - } - } - AddNode(ParseNodeKind::VariableDeclaration, end_token, state.subtree_start, - state.has_error); -} - -auto Parser::HandleVarFinishAsForState() -> void { - auto state = PopState(); - - auto end_token = state.token; - if (PositionIs(TokenKind::In)) { - end_token = Consume(); - } else if (PositionIs(TokenKind::Colon)) { - CARBON_DIAGNOSTIC(ExpectedInNotColon, Error, - "`:` should be replaced by `in`."); - emitter_->Emit(*position_, ExpectedInNotColon); - state.has_error = true; - end_token = Consume(); - } else { - CARBON_DIAGNOSTIC(ExpectedIn, Error, - "Expected `in` after loop `var` declaration."); - emitter_->Emit(*position_, ExpectedIn); - state.has_error = true; - } - - AddNode(ParseNodeKind::ForIn, end_token, state.subtree_start, - state.has_error); -} - -} // namespace Carbon diff --git a/toolchain/parser/parser_context.cpp b/toolchain/parser/parser_context.cpp new file mode 100644 index 0000000000000..00c9fabc2050f --- /dev/null +++ b/toolchain/parser/parser_context.cpp @@ -0,0 +1,457 @@ +// 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 "toolchain/parser/parser_context.h" + +#include +#include +#include + +#include "common/check.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "toolchain/lexer/token_kind.h" +#include "toolchain/lexer/tokenized_buffer.h" +#include "toolchain/parser/parse_node_kind.h" +#include "toolchain/parser/parse_tree.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// A relative location for characters in errors. +enum class RelativeLocation : int8_t { + Around, + After, + Before, +}; + +// Adapts RelativeLocation for use with formatv. +static auto operator<<(llvm::raw_ostream& out, RelativeLocation loc) + -> llvm::raw_ostream& { + switch (loc) { + case RelativeLocation::Around: + out << "around"; + break; + case RelativeLocation::After: + out << "after"; + break; + case RelativeLocation::Before: + out << "before"; + break; + } + return out; +} + +class PrettyStackTraceParseState : public llvm::PrettyStackTraceEntry { + public: + explicit PrettyStackTraceParseState(const ParserContext* context) + : context_(context) {} + ~PrettyStackTraceParseState() override = default; + + auto print(llvm::raw_ostream& output) const -> void override { + output << "Parser stack:\n"; + for (int i = 0; i < static_cast(context_->state_stack().size()); ++i) { + const auto& entry = context_->state_stack()[i]; + output << "\t" << i << ".\t" << entry.state; + Print(output, entry.token); + } + output << "\tcursor\tposition_"; + Print(output, *context_->position()); + } + + private: + auto Print(llvm::raw_ostream& output, TokenizedBuffer::Token token) const + -> void { + auto line = context_->tokens().GetLine(token); + output << " @ " << context_->tokens().GetLineNumber(line) << ":" + << context_->tokens().GetColumnNumber(token) << ":" + << " token " << token << " : " << context_->tokens().GetKind(token) + << "\n"; + } + + const ParserContext* context_; +}; + +ParserContext::ParserContext(ParseTree& tree, TokenizedBuffer& tokens, + TokenDiagnosticEmitter& emitter, + llvm::raw_ostream* vlog_stream) + : tree_(&tree), + tokens_(&tokens), + emitter_(&emitter), + vlog_stream_(vlog_stream), + position_(tokens_->tokens().begin()), + end_(tokens_->tokens().end()) { + CARBON_CHECK(position_ != end_) << "Empty TokenizedBuffer"; + --end_; + CARBON_CHECK(tokens_->GetKind(*end_) == TokenKind::EndOfFile) + << "TokenizedBuffer should end with EndOfFile, ended with " + << tokens_->GetKind(*end_); +} + +auto ParserContext::AddLeafNode(ParseNodeKind kind, + TokenizedBuffer::Token token, bool has_error) + -> void { + tree_->node_impls_.push_back( + ParseTree::NodeImpl(kind, has_error, token, /*subtree_size=*/1)); + if (has_error) { + tree_->has_errors_ = true; + } +} + +auto ParserContext::AddNode(ParseNodeKind kind, TokenizedBuffer::Token token, + int subtree_start, bool has_error) -> void { + int subtree_size = tree_->size() - subtree_start + 1; + tree_->node_impls_.push_back( + ParseTree::NodeImpl(kind, has_error, token, subtree_size)); + if (has_error) { + tree_->has_errors_ = true; + } +} + +auto ParserContext::ConsumeAndAddOpenParen(TokenizedBuffer::Token default_token, + ParseNodeKind start_kind) -> void { + if (auto open_paren = ConsumeIf(TokenKind::OpenParen)) { + AddLeafNode(start_kind, *open_paren, /*has_error=*/false); + } else { + CARBON_DIAGNOSTIC(ExpectedParenAfter, Error, "Expected `(` after `{0}`.", + TokenKind); + emitter_->Emit(*position_, ExpectedParenAfter, + tokens().GetKind(default_token)); + AddLeafNode(start_kind, default_token, /*has_error=*/true); + } +} + +auto ParserContext::ConsumeAndAddCloseParen(StateStackEntry state, + ParseNodeKind close_kind) -> void { + // state.token should point at the introducer, with the paren one after the + // introducer. + auto expected_paren = *(TokenizedBuffer::TokenIterator(state.token) + 1); + + if (tokens().GetKind(expected_paren) != TokenKind::OpenParen) { + AddNode(close_kind, state.token, state.subtree_start, /*has_error=*/true); + } else if (auto close_token = ConsumeIf(TokenKind::CloseParen)) { + AddNode(close_kind, *close_token, state.subtree_start, state.has_error); + } else { + // TODO: Include the location of the matching open_paren in the diagnostic. + CARBON_DIAGNOSTIC(ExpectedCloseParen, Error, + "Unexpected tokens before `)`."); + emitter_->Emit(*position_, ExpectedCloseParen); + + SkipTo(tokens().GetMatchedClosingToken(expected_paren)); + AddNode(close_kind, Consume(), state.subtree_start, /*has_error=*/true); + } +} + +auto ParserContext::ConsumeAndAddLeafNodeIf(TokenKind token_kind, + ParseNodeKind node_kind) -> bool { + auto token = ConsumeIf(token_kind); + if (!token) { + return false; + } + + AddLeafNode(node_kind, *token); + return true; +} + +auto ParserContext::ConsumeChecked(TokenKind kind) -> TokenizedBuffer::Token { + CARBON_CHECK(PositionIs(kind)) + << "Required " << kind << ", found " << PositionKind(); + return Consume(); +} + +auto ParserContext::ConsumeIf(TokenKind kind) + -> std::optional { + if (!PositionIs(kind)) { + return std::nullopt; + } + return Consume(); +} + +auto ParserContext::ConsumeIfPatternKeyword(TokenKind keyword_token, + ParserState keyword_state, + int subtree_start) -> void { + if (auto token = ConsumeIf(keyword_token)) { + PushState(ParserContext::StateStackEntry( + keyword_state, PrecedenceGroup::ForTopLevelExpression(), + PrecedenceGroup::ForTopLevelExpression(), *token, subtree_start)); + } +} + +auto ParserContext::FindNextOf(std::initializer_list desired_kinds) + -> std::optional { + auto new_position = position_; + while (true) { + TokenizedBuffer::Token token = *new_position; + TokenKind kind = tokens().GetKind(token); + if (kind.IsOneOf(desired_kinds)) { + return token; + } + + // Step to the next token at the current bracketing level. + if (kind.is_closing_symbol() || kind == TokenKind::EndOfFile) { + // There are no more tokens at this level. + return std::nullopt; + } else if (kind.is_opening_symbol()) { + new_position = TokenizedBuffer::TokenIterator( + tokens().GetMatchedClosingToken(token)); + // Advance past the closing token. + ++new_position; + } else { + ++new_position; + } + } +} + +auto ParserContext::SkipMatchingGroup() -> bool { + if (!PositionKind().is_opening_symbol()) { + return false; + } + + SkipTo(tokens().GetMatchedClosingToken(*position_)); + ++position_; + return true; +} + +auto ParserContext::SkipPastLikelyEnd(TokenizedBuffer::Token skip_root) + -> std::optional { + if (position_ == end_) { + return std::nullopt; + } + + TokenizedBuffer::Line root_line = tokens().GetLine(skip_root); + int root_line_indent = tokens().GetIndentColumnNumber(root_line); + + // We will keep scanning through tokens on the same line as the root or + // lines with greater indentation than root's line. + auto is_same_line_or_indent_greater_than_root = + [&](TokenizedBuffer::Token t) { + TokenizedBuffer::Line l = tokens().GetLine(t); + if (l == root_line) { + return true; + } + + return tokens().GetIndentColumnNumber(l) > root_line_indent; + }; + + do { + if (PositionIs(TokenKind::CloseCurlyBrace)) { + // Immediately bail out if we hit an unmatched close curly, this will + // pop us up a level of the syntax grouping. + return std::nullopt; + } + + // We assume that a semicolon is always intended to be the end of the + // current construct. + if (auto semi = ConsumeIf(TokenKind::Semi)) { + return semi; + } + + // Skip over any matching group of tokens(). + if (SkipMatchingGroup()) { + continue; + } + + // Otherwise just step forward one token. + ++position_; + } while (position_ != end_ && + is_same_line_or_indent_greater_than_root(*position_)); + + return std::nullopt; +} + +auto ParserContext::SkipTo(TokenizedBuffer::Token t) -> void { + CARBON_CHECK(t >= *position_) << "Tried to skip backwards from " << position_ + << " to " << TokenizedBuffer::TokenIterator(t); + position_ = TokenizedBuffer::TokenIterator(t); + CARBON_CHECK(position_ != end_) << "Skipped past EOF."; +} + +// Determines whether the given token is considered to be the start of an +// operand according to the rules for infix operator parsing. +static auto IsAssumedStartOfOperand(TokenKind kind) -> bool { + return kind.IsOneOf({TokenKind::OpenParen, TokenKind::Identifier, + TokenKind::IntegerLiteral, TokenKind::RealLiteral, + TokenKind::StringLiteral}); +} + +// Determines whether the given token is considered to be the end of an +// operand according to the rules for infix operator parsing. +static auto IsAssumedEndOfOperand(TokenKind kind) -> bool { + return kind.IsOneOf({TokenKind::CloseParen, TokenKind::CloseCurlyBrace, + TokenKind::CloseSquareBracket, TokenKind::Identifier, + TokenKind::IntegerLiteral, TokenKind::RealLiteral, + TokenKind::StringLiteral}); +} + +// Determines whether the given token could possibly be the start of an +// operand. This is conservatively correct, and will never incorrectly return +// `false`, but can incorrectly return `true`. +static auto IsPossibleStartOfOperand(TokenKind kind) -> bool { + return !kind.IsOneOf({TokenKind::CloseParen, TokenKind::CloseCurlyBrace, + TokenKind::CloseSquareBracket, TokenKind::Comma, + TokenKind::Semi, TokenKind::Colon}); +} + +auto ParserContext::IsLexicallyValidInfixOperator() -> bool { + CARBON_CHECK(position_ != end_) << "Expected an operator token."; + + bool leading_space = tokens().HasLeadingWhitespace(*position_); + bool trailing_space = tokens().HasTrailingWhitespace(*position_); + + // If there's whitespace on both sides, it's an infix operator. + if (leading_space && trailing_space) { + return true; + } + + // If there's whitespace on exactly one side, it's not an infix operator. + if (leading_space || trailing_space) { + return false; + } + + // Otherwise, for an infix operator, the preceding token must be any close + // bracket, identifier, or literal and the next token must be an open paren, + // identifier, or literal. + if (position_ == tokens().tokens().begin() || + !IsAssumedEndOfOperand(tokens().GetKind(*(position_ - 1))) || + !IsAssumedStartOfOperand(tokens().GetKind(*(position_ + 1)))) { + return false; + } + + return true; +} + +auto ParserContext::IsTrailingOperatorInfix() -> bool { + if (position_ == end_) { + return false; + } + + // An operator that follows the infix operator rules is parsed as + // infix, unless the next token means that it can't possibly be. + if (IsLexicallyValidInfixOperator() && + IsPossibleStartOfOperand(tokens().GetKind(*(position_ + 1)))) { + return true; + } + + // A trailing operator with leading whitespace that's not valid as infix is + // not valid at all. If the next token looks like the start of an operand, + // then parse as infix, otherwise as postfix. Either way we'll produce a + // diagnostic later on. + if (tokens().HasLeadingWhitespace(*position_) && + IsAssumedStartOfOperand(tokens().GetKind(*(position_ + 1)))) { + return true; + } + + return false; +} + +auto ParserContext::DiagnoseOperatorFixity(OperatorFixity fixity) -> void { + if (fixity == OperatorFixity::Infix) { + // Infix operators must satisfy the infix operator rules. + if (!IsLexicallyValidInfixOperator()) { + CARBON_DIAGNOSTIC(BinaryOperatorRequiresWhitespace, Error, + "Whitespace missing {0} binary operator.", + RelativeLocation); + emitter_->Emit(*position_, BinaryOperatorRequiresWhitespace, + tokens().HasLeadingWhitespace(*position_) + ? RelativeLocation::After + : (tokens().HasTrailingWhitespace(*position_) + ? RelativeLocation::Before + : RelativeLocation::Around)); + } + } else { + bool prefix = fixity == OperatorFixity::Prefix; + + // Whitespace is not permitted between a symbolic pre/postfix operator and + // its operand. + if (PositionKind().is_symbol() && + (prefix ? tokens().HasTrailingWhitespace(*position_) + : tokens().HasLeadingWhitespace(*position_))) { + CARBON_DIAGNOSTIC(UnaryOperatorHasWhitespace, Error, + "Whitespace is not allowed {0} this unary operator.", + RelativeLocation); + emitter_->Emit( + *position_, UnaryOperatorHasWhitespace, + prefix ? RelativeLocation::After : RelativeLocation::Before); + } + // Pre/postfix operators must not satisfy the infix operator rules. + if (IsLexicallyValidInfixOperator()) { + CARBON_DIAGNOSTIC(UnaryOperatorRequiresWhitespace, Error, + "Whitespace is required {0} this unary operator.", + RelativeLocation); + emitter_->Emit( + *position_, UnaryOperatorRequiresWhitespace, + prefix ? RelativeLocation::Before : RelativeLocation::After); + } + } +} + +auto ParserContext::ConsumeListToken(ParseNodeKind comma_kind, + TokenKind close_kind, + bool already_has_error) -> ListTokenKind { + if (!PositionIs(TokenKind::Comma) && !PositionIs(close_kind)) { + // Don't error a second time on the same element. + if (!already_has_error) { + CARBON_DIAGNOSTIC(UnexpectedTokenAfterListElement, Error, + "Expected `,` or `{0}`.", TokenKind); + emitter_->Emit(*position_, UnexpectedTokenAfterListElement, close_kind); + ReturnErrorOnState(); + } + + // Recover from the invalid token. + auto end_of_element = FindNextOf({TokenKind::Comma, close_kind}); + // The lexer guarantees that parentheses are balanced. + CARBON_CHECK(end_of_element) + << "missing matching `" << close_kind.opening_symbol() << "` for `" + << close_kind << "`"; + + SkipTo(*end_of_element); + } + + if (PositionIs(close_kind)) { + return ListTokenKind::Close; + } else { + AddLeafNode(comma_kind, Consume()); + return PositionIs(close_kind) ? ListTokenKind::CommaClose + : ListTokenKind::Comma; + } +} + +auto ParserContext::GetDeclarationContext() -> DeclarationContext { + // i == 0 is the file-level DeclarationScopeLoop. Additionally, i == 1 can be + // skipped because it will never be a DeclarationScopeLoop. + for (int i = state_stack_.size() - 1; i > 1; --i) { + // The declaration context is always the state _above_ a + // DeclarationScopeLoop. + if (state_stack_[i].state == ParserState::DeclarationScopeLoop) { + switch (state_stack_[i - 1].state) { + case ParserState::TypeDefinitionFinishAsClass: + return DeclarationContext::Class; + case ParserState::TypeDefinitionFinishAsInterface: + return DeclarationContext::Interface; + case ParserState::TypeDefinitionFinishAsNamedConstraint: + return DeclarationContext::NamedConstraint; + default: + llvm_unreachable("Missing handling for a declaration scope"); + } + } + } + CARBON_CHECK(!state_stack_.empty() && + state_stack_[0].state == ParserState::DeclarationScopeLoop); + return DeclarationContext::File; +} + +auto ParserContext::RecoverFromDeclarationError(StateStackEntry state, + ParseNodeKind parse_node_kind, + bool skip_past_likely_end) + -> void { + auto token = state.token; + if (skip_past_likely_end) { + if (auto semi = SkipPastLikelyEnd(token)) { + token = *semi; + } + } + AddNode(parse_node_kind, token, state.subtree_start, + /*has_error=*/true); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser.h b/toolchain/parser/parser_context.h similarity index 71% rename from toolchain/parser/parser.h rename to toolchain/parser/parser_context.h index 6e3196c18c733..f0c746900d64f 100644 --- a/toolchain/parser/parser.h +++ b/toolchain/parser/parser_context.h @@ -2,8 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef CARBON_TOOLCHAIN_PARSER_PARSER_H_ -#define CARBON_TOOLCHAIN_PARSER_PARSER_H_ +#ifndef CARBON_TOOLCHAIN_PARSER_PARSER_CONTEXT_H_ +#define CARBON_TOOLCHAIN_PARSER_PARSER_CONTEXT_H_ #include @@ -20,20 +20,8 @@ namespace Carbon { // This parser uses a stack for state transitions. See parser_state.def for // state documentation. -class Parser { +class ParserContext { public: - // Parses the tokens into a parse tree, emitting any errors encountered. - // - // This is the entry point to the parser implementation. - static auto Parse(TokenizedBuffer& tokens, TokenDiagnosticEmitter& emitter, - llvm::raw_ostream* vlog_stream) -> ParseTree { - ParseTree tree(tokens); - Parser parser(tree, tokens, emitter, vlog_stream); - parser.Parse(); - return tree; - } - - private: // Possible operator fixities for errors. enum class OperatorFixity { Prefix, Infix, Postfix }; @@ -106,11 +94,9 @@ class Parser { static_assert(sizeof(StateStackEntry) == 12, "StateStackEntry has unexpected size!"); - explicit Parser(ParseTree& tree, TokenizedBuffer& tokens, - TokenDiagnosticEmitter& emitter, - llvm::raw_ostream* vlog_stream); - - auto Parse() -> void; + explicit ParserContext(ParseTree& tree, TokenizedBuffer& tokens, + TokenDiagnosticEmitter& emitter, + llvm::raw_ostream* vlog_stream); // Adds a node to the parse tree that has no children (a leaf). auto AddLeafNode(ParseNodeKind kind, TokenizedBuffer::Token token, @@ -264,106 +250,40 @@ class Parser { // DeclarationScopeLoop. auto GetDeclarationContext() -> DeclarationContext; - // Handles error recovery in a declaration, particularly before any possible - // definition has started (although one could be present). Recover to a - // semicolon when it makes sense as a possible end, otherwise use the - // introducer token for the error. - auto HandleDeclarationError(StateStackEntry state, - ParseNodeKind parse_node_kind, - bool skip_past_likely_end) -> void; - - // Handles an unrecognized declaration, adding an error node. - auto HandleUnrecognizedDeclaration() -> void; - // Propagates an error up the state stack, to the parent state. auto ReturnErrorOnState() -> void { state_stack_.back().has_error = true; } - // Prints a diagnostic for brace expression syntax errors. - auto HandleBraceExpressionParameterError(StateStackEntry state, - ParserState param_finish_state) - -> void; - - // Handles BraceExpressionParameterAs(Type|Value|Unknown). - auto HandleBraceExpressionParameter(ParserState after_designator_state, - ParserState param_finish_state) -> void; - - // Handles BraceExpressionParameterAfterDesignatorAs(Type|Value|Unknown). - auto HandleBraceExpressionParameterAfterDesignator( - ParserState param_finish_state) -> void; - - // Handles BraceExpressionParameterFinishAs(Type|Value|Unknown). - auto HandleBraceExpressionParameterFinish(ParseNodeKind node_kind, - ParserState param_state) -> void; - - // Handles BraceExpressionFinishAs(Type|Value|Unknown). - auto HandleBraceExpressionFinish(ParseNodeKind node_kind) -> void; - - // Handles DeclarationNameAndParamsAs(Optional|Required). - auto HandleDeclarationNameAndParams(bool params_required) -> void; - - // Handles DesignatorAs. - auto HandleDesignator(bool as_struct) -> void; - - // Handles ParameterAs(Deduced|Regular). - auto HandleParameter(ParserState pattern_state, ParserState finish_state) - -> void; - - // Handles ParameterFinishAs(Deduced|Regular). - auto HandleParameterFinish(TokenKind close_token, ParserState param_state) - -> void; - - // Handles ParameterListAs(Deduced|Regular). - auto HandleParameterList(ParseNodeKind parse_node_kind, - TokenKind open_token_kind, - TokenKind close_token_kind, ParserState param_state, - ParserState finish_state) -> void; - - // Handles ParameterListFinishAs(Deduced|Regular). - auto HandleParameterListFinish(ParseNodeKind parse_node_kind, - TokenKind token_kind) -> void; - - // Handles ParenConditionAs(If|While) - auto HandleParenCondition(ParseNodeKind start_kind, ParserState finish_state) - -> void; - - // Handles ParenExpressionParameterFinishAs(Unknown|Tuple). - auto HandleParenExpressionParameterFinish(bool as_tuple) -> void; - - // Handles PatternAs(DeducedParameter|FunctionParameter|Variable). - auto HandlePattern(PatternKind pattern_kind) -> void; - - // Handles PatternFinishAs(Generic|Regular). - auto HandlePatternFinish(ParseNodeKind node_kind) -> void; - - // For HandlePattern, tries to consume a wrapping keyword. + // For ParserHandlePattern, tries to consume a wrapping keyword. auto ConsumeIfPatternKeyword(TokenKind keyword_token, ParserState keyword_state, int subtree_start) -> void; - // Handles the `;` after a keyword statement. - auto HandleStatementKeywordFinish(ParseNodeKind node_kind) -> void; + // Handles error recovery in a declaration, particularly before any possible + // definition has started (although one could be present). Recover to a + // semicolon when it makes sense as a possible end, otherwise use the + // introducer token for the error. + auto RecoverFromDeclarationError(StateStackEntry state, + ParseNodeKind parse_node_kind, + bool skip_past_likely_end) -> void; - // Handles processing of a type's introducer. - auto HandleTypeIntroducer(ParseNodeKind introducer_kind, - ParserState after_params_state) -> void; + auto tree() const -> const ParseTree& { return *tree_; } - // Handles processing after params, deciding whether it's a declaration or - // definition. - auto HandleTypeAfterParams(ParseNodeKind declaration_kind, - ParseNodeKind definition_start_kind, - ParserState definition_finish_state) -> void; + auto tokens() const -> const TokenizedBuffer& { return *tokens_; } - // Handles parsing after the declaration scope of a type. - auto HandleTypeDefinitionFinish(ParseNodeKind definition_kind) -> void; + auto emitter() -> TokenDiagnosticEmitter& { return *emitter_; } - // Handles VarAs(Semicolon|For). - auto HandleVar(ParserState finish_state) -> void; + auto position() -> TokenizedBuffer::TokenIterator& { return position_; } + auto position() const -> TokenizedBuffer::TokenIterator { return position_; } - // `clang-format` has a bug with spacing around `->` returns in macros. See - // https://bugs.llvm.org/show_bug.cgi?id=48320 for details. -#define CARBON_PARSER_STATE(Name) auto Handle##Name##State()->void; -#include "toolchain/parser/parser_state.def" + auto state_stack() -> llvm::SmallVector& { + return state_stack_; + } + auto state_stack() const -> const llvm::SmallVector& { + return state_stack_; + } + + private: ParseTree* tree_; TokenizedBuffer* tokens_; TokenDiagnosticEmitter* emitter_; @@ -379,6 +299,29 @@ class Parser { llvm::SmallVector state_stack_; }; +// Parses the tokens into a parse tree, emitting any errors encountered. +// +// This is the entry point to the parser implementation. +auto Parse(TokenizedBuffer& tokens, TokenDiagnosticEmitter& emitter, + llvm::raw_ostream* vlog_stream) -> ParseTree; + +// The diagnostics below may be emitted a couple different ways as part of +// operator parsing. + +CARBON_DIAGNOSTIC( + OperatorRequiresParentheses, Error, + "Parentheses are required to disambiguate operator precedence."); + +CARBON_DIAGNOSTIC(ExpectedSemiAfterExpression, Error, + "Expected `;` after expression."); + +CARBON_DIAGNOSTIC(ExpectedDeclarationName, Error, + "`{0}` introducer should be followed by a name.", TokenKind); +CARBON_DIAGNOSTIC(ExpectedDeclarationSemiOrDefinition, Error, + "`{0}` should either end with a `;` for a declaration or " + "have a `{{ ... }` block for a definition.", + TokenKind); + } // namespace Carbon -#endif // CARBON_TOOLCHAIN_PARSER_PARSER_H_ +#endif // CARBON_TOOLCHAIN_PARSER_PARSER_CONTEXT_H_ diff --git a/toolchain/parser/parser_handle_brace_expression.cpp b/toolchain/parser/parser_handle_brace_expression.cpp new file mode 100644 index 0000000000000..6b54eb0e07ca7 --- /dev/null +++ b/toolchain/parser/parser_handle_brace_expression.cpp @@ -0,0 +1,230 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleBraceExpression(ParserContext& context) -> void { + auto state = context.PopState(); + + state.state = ParserState::BraceExpressionFinishAsUnknown; + context.PushState(state); + + CARBON_CHECK(context.ConsumeAndAddLeafNodeIf( + TokenKind::OpenCurlyBrace, + ParseNodeKind::StructLiteralOrStructTypeLiteralStart)); + if (!context.PositionIs(TokenKind::CloseCurlyBrace)) { + context.PushState(ParserState::BraceExpressionParameterAsUnknown); + } +} + +// Prints a diagnostic for brace expression syntax errors. +static auto ParserHandleBraceExpressionParameterError( + ParserContext& context, ParserContext::StateStackEntry state, + ParserState param_finish_state) -> void { + bool is_type = + param_finish_state == ParserState::BraceExpressionParameterFinishAsType; + bool is_value = + param_finish_state == ParserState::BraceExpressionParameterFinishAsValue; + bool is_unknown = param_finish_state == + ParserState::BraceExpressionParameterFinishAsUnknown; + CARBON_CHECK(is_type || is_value || is_unknown); + CARBON_DIAGNOSTIC(ExpectedStructLiteralField, Error, "Expected {0}{1}{2}.", + llvm::StringRef, llvm::StringRef, llvm::StringRef); + context.emitter().Emit(*context.position(), ExpectedStructLiteralField, + (is_type || is_unknown) ? "`.field: field_type`" : "", + is_unknown ? " or " : "", + (is_value || is_unknown) ? "`.field = value`" : ""); + + state.state = param_finish_state; + state.has_error = true; + context.PushState(state); +} + +// Handles BraceExpressionParameterAs(Type|Value|Unknown). +static auto ParserHandleBraceExpressionParameter( + ParserContext& context, ParserState after_designator_state, + ParserState param_finish_state) -> void { + auto state = context.PopState(); + + if (!context.PositionIs(TokenKind::Period)) { + ParserHandleBraceExpressionParameterError(context, state, + param_finish_state); + return; + } + + state.state = after_designator_state; + context.PushState(state); + context.PushState(ParserState::DesignatorAsStruct); +} + +auto ParserHandleBraceExpressionParameterAsType(ParserContext& context) + -> void { + ParserHandleBraceExpressionParameter( + context, ParserState::BraceExpressionParameterAfterDesignatorAsType, + ParserState::BraceExpressionParameterFinishAsType); +} + +auto ParserHandleBraceExpressionParameterAsValue(ParserContext& context) + -> void { + ParserHandleBraceExpressionParameter( + context, ParserState::BraceExpressionParameterAfterDesignatorAsValue, + ParserState::BraceExpressionParameterFinishAsValue); +} + +auto ParserHandleBraceExpressionParameterAsUnknown(ParserContext& context) + -> void { + ParserHandleBraceExpressionParameter( + context, ParserState::BraceExpressionParameterAfterDesignatorAsUnknown, + ParserState::BraceExpressionParameterFinishAsUnknown); +} + +// Handles BraceExpressionParameterAfterDesignatorAs(Type|Value|Unknown). +static auto ParserHandleBraceExpressionParameterAfterDesignator( + ParserContext& context, ParserState param_finish_state) -> void { + auto state = context.PopState(); + + if (state.has_error) { + auto recovery_pos = context.FindNextOf( + {TokenKind::Equal, TokenKind::Colon, TokenKind::Comma}); + if (!recovery_pos || + context.tokens().GetKind(*recovery_pos) == TokenKind::Comma) { + state.state = param_finish_state; + context.PushState(state); + return; + } + context.SkipTo(*recovery_pos); + } + + // Work out the kind of this element. + bool is_type; + if (context.PositionIs(TokenKind::Colon)) { + is_type = true; + } else if (context.PositionIs(TokenKind::Equal)) { + is_type = false; + } else { + ParserHandleBraceExpressionParameterError(context, state, + param_finish_state); + return; + } + + // If we're changing from unknown, update the related finish states. + if (param_finish_state == + ParserState::BraceExpressionParameterFinishAsUnknown) { + auto finish_state = context.PopState(); + CARBON_CHECK(finish_state.state == + ParserState::BraceExpressionFinishAsUnknown); + if (is_type) { + finish_state.state = ParserState::BraceExpressionFinishAsType; + param_finish_state = ParserState::BraceExpressionParameterFinishAsType; + } else { + finish_state.state = ParserState::BraceExpressionFinishAsValue; + param_finish_state = ParserState::BraceExpressionParameterFinishAsValue; + } + context.PushState(finish_state); + } + + auto want_param_finish_state = + is_type ? ParserState::BraceExpressionParameterFinishAsType + : ParserState::BraceExpressionParameterFinishAsValue; + if (param_finish_state != want_param_finish_state) { + ParserHandleBraceExpressionParameterError(context, state, + param_finish_state); + return; + } + + // Struct type fields and value fields use the same grammar except + // that one has a `:` separator and the other has an `=` separator. + state.state = param_finish_state; + state.token = context.Consume(); + context.PushState(state); + context.PushState(ParserState::Expression); +} + +auto ParserHandleBraceExpressionParameterAfterDesignatorAsType( + ParserContext& context) -> void { + ParserHandleBraceExpressionParameterAfterDesignator( + context, ParserState::BraceExpressionParameterFinishAsType); +} + +auto ParserHandleBraceExpressionParameterAfterDesignatorAsValue( + ParserContext& context) -> void { + ParserHandleBraceExpressionParameterAfterDesignator( + context, ParserState::BraceExpressionParameterFinishAsValue); +} + +auto ParserHandleBraceExpressionParameterAfterDesignatorAsUnknown( + ParserContext& context) -> void { + ParserHandleBraceExpressionParameterAfterDesignator( + context, ParserState::BraceExpressionParameterFinishAsUnknown); +} + +// Handles BraceExpressionParameterFinishAs(Type|Value|Unknown). +static auto ParserHandleBraceExpressionParameterFinish(ParserContext& context, + ParseNodeKind node_kind, + ParserState param_state) + -> void { + auto state = context.PopState(); + + if (state.has_error) { + context.AddLeafNode(ParseNodeKind::StructFieldUnknown, state.token, + /*has_error=*/true); + } else { + context.AddNode(node_kind, state.token, state.subtree_start, + /*has_error=*/false); + } + + if (context.ConsumeListToken(ParseNodeKind::StructComma, + TokenKind::CloseCurlyBrace, state.has_error) == + ParserContext::ListTokenKind::Comma) { + context.PushState(param_state); + } +} + +auto ParserHandleBraceExpressionParameterFinishAsType(ParserContext& context) + -> void { + ParserHandleBraceExpressionParameterFinish( + context, ParseNodeKind::StructFieldType, + ParserState::BraceExpressionParameterAsType); +} + +auto ParserHandleBraceExpressionParameterFinishAsValue(ParserContext& context) + -> void { + ParserHandleBraceExpressionParameterFinish( + context, ParseNodeKind::StructFieldValue, + ParserState::BraceExpressionParameterAsValue); +} + +auto ParserHandleBraceExpressionParameterFinishAsUnknown(ParserContext& context) + -> void { + ParserHandleBraceExpressionParameterFinish( + context, ParseNodeKind::StructFieldUnknown, + ParserState::BraceExpressionParameterAsUnknown); +} + +// Handles BraceExpressionFinishAs(Type|Value|Unknown). +static auto ParserHandleBraceExpressionFinish(ParserContext& context, + ParseNodeKind node_kind) -> void { + auto state = context.PopState(); + + context.AddNode(node_kind, context.Consume(), state.subtree_start, + state.has_error); +} + +auto ParserHandleBraceExpressionFinishAsType(ParserContext& context) -> void { + ParserHandleBraceExpressionFinish(context, ParseNodeKind::StructTypeLiteral); +} + +auto ParserHandleBraceExpressionFinishAsValue(ParserContext& context) -> void { + ParserHandleBraceExpressionFinish(context, ParseNodeKind::StructLiteral); +} + +auto ParserHandleBraceExpressionFinishAsUnknown(ParserContext& context) + -> void { + ParserHandleBraceExpressionFinish(context, ParseNodeKind::StructLiteral); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_call_expression.cpp b/toolchain/parser/parser_handle_call_expression.cpp new file mode 100644 index 0000000000000..ca52b078766cc --- /dev/null +++ b/toolchain/parser/parser_handle_call_expression.cpp @@ -0,0 +1,46 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleCallExpression(ParserContext& context) -> void { + auto state = context.PopState(); + + state.state = ParserState::CallExpressionFinish; + context.PushState(state); + + context.AddNode(ParseNodeKind::CallExpressionStart, context.Consume(), + state.subtree_start, state.has_error); + if (!context.PositionIs(TokenKind::CloseParen)) { + context.PushState(ParserState::CallExpressionParameterFinish); + context.PushState(ParserState::Expression); + } +} + +auto ParserHandleCallExpressionParameterFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + if (state.has_error) { + context.ReturnErrorOnState(); + } + + if (context.ConsumeListToken(ParseNodeKind::CallExpressionComma, + TokenKind::CloseParen, state.has_error) == + ParserContext::ListTokenKind::Comma) { + context.PushState(ParserState::CallExpressionParameterFinish); + context.PushState(ParserState::Expression); + } +} + +auto ParserHandleCallExpressionFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::CallExpression, context.Consume(), + state.subtree_start, state.has_error); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_code_block.cpp b/toolchain/parser/parser_handle_code_block.cpp new file mode 100644 index 0000000000000..9b2c20b3b222d --- /dev/null +++ b/toolchain/parser/parser_handle_code_block.cpp @@ -0,0 +1,42 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleCodeBlock(ParserContext& context) -> void { + context.PopAndDiscardState(); + + context.PushState(ParserState::CodeBlockFinish); + if (context.ConsumeAndAddLeafNodeIf(TokenKind::OpenCurlyBrace, + ParseNodeKind::CodeBlockStart)) { + context.PushState(ParserState::StatementScopeLoop); + } else { + context.AddLeafNode(ParseNodeKind::CodeBlockStart, *context.position(), + /*has_error=*/true); + + // Recover by parsing a single statement. + CARBON_DIAGNOSTIC(ExpectedCodeBlock, Error, "Expected braced code block."); + context.emitter().Emit(*context.position(), ExpectedCodeBlock); + + context.PushState(ParserState::Statement); + } +} + +auto ParserHandleCodeBlockFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + // If the block started with an open curly, this is a close curly. + if (context.tokens().GetKind(state.token) == TokenKind::OpenCurlyBrace) { + context.AddNode(ParseNodeKind::CodeBlock, context.Consume(), + state.subtree_start, state.has_error); + } else { + context.AddNode(ParseNodeKind::CodeBlock, state.token, state.subtree_start, + /*has_error=*/true); + } +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_declaration_name_and_params.cpp b/toolchain/parser/parser_handle_declaration_name_and_params.cpp new file mode 100644 index 0000000000000..f12c2c384ee37 --- /dev/null +++ b/toolchain/parser/parser_handle_declaration_name_and_params.cpp @@ -0,0 +1,62 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles DeclarationNameAndParamsAs(Optional|Required). +static auto ParserHandleDeclarationNameAndParams(ParserContext& context, + bool params_required) -> void { + auto state = context.PopState(); + + if (!context.ConsumeAndAddLeafNodeIf(TokenKind::Identifier, + ParseNodeKind::DeclaredName)) { + context.emitter().Emit(*context.position(), ExpectedDeclarationName, + context.tokens().GetKind(state.token)); + context.ReturnErrorOnState(); + return; + } + + if (context.PositionIs(TokenKind::OpenSquareBracket)) { + context.PushState(ParserState::DeclarationNameAndParamsAfterDeduced); + context.PushState(ParserState::ParameterListAsDeduced); + } else if (context.PositionIs(TokenKind::OpenParen)) { + context.PushState(ParserState::ParameterListAsRegular); + } else if (params_required) { + CARBON_DIAGNOSTIC(ParametersRequiredByIntroducer, Error, + "`{0}` requires a `(` for parameters.", TokenKind); + context.emitter().Emit(*context.position(), ParametersRequiredByIntroducer, + context.tokens().GetKind(state.token)); + context.ReturnErrorOnState(); + } +} + +auto ParserHandleDeclarationNameAndParamsAsOptional(ParserContext& context) + -> void { + ParserHandleDeclarationNameAndParams(context, /*params_required=*/false); +} + +auto ParserHandleDeclarationNameAndParamsAsRequired(ParserContext& context) + -> void { + ParserHandleDeclarationNameAndParams(context, /*params_required=*/true); +} + +auto ParserHandleDeclarationNameAndParamsAfterDeduced(ParserContext& context) + -> void { + context.PopAndDiscardState(); + + if (context.PositionIs(TokenKind::OpenParen)) { + context.PushState(ParserState::ParameterListAsRegular); + } else { + CARBON_DIAGNOSTIC( + ParametersRequiredByDeduced, Error, + "A `(` for parameters is required after deduced parameters."); + context.emitter().Emit(*context.position(), ParametersRequiredByDeduced); + context.ReturnErrorOnState(); + } +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_declaration_scope_loop.cpp b/toolchain/parser/parser_handle_declaration_scope_loop.cpp new file mode 100644 index 0000000000000..0ec8b253341e2 --- /dev/null +++ b/toolchain/parser/parser_handle_declaration_scope_loop.cpp @@ -0,0 +1,65 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles an unrecognized declaration, adding an error node. +static auto ParserHandleUnrecognizedDeclaration(ParserContext& context) + -> void { + CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error, + "Unrecognized declaration introducer."); + context.emitter().Emit(*context.position(), UnrecognizedDeclaration); + auto cursor = *context.position(); + auto semi = context.SkipPastLikelyEnd(cursor); + // Locate the EmptyDeclaration at the semi when found, but use the + // original cursor location for an error when not. + context.AddLeafNode(ParseNodeKind::EmptyDeclaration, semi ? *semi : cursor, + /*has_error=*/true); +} + +auto ParserHandleDeclarationScopeLoop(ParserContext& context) -> void { + // This maintains the current state unless we're at the end of the scope. + + switch (context.PositionKind()) { + case TokenKind::CloseCurlyBrace: + case TokenKind::EndOfFile: { + // This is the end of the scope, so the loop state ends. + context.PopAndDiscardState(); + break; + } + case TokenKind::Class: { + context.PushState(ParserState::TypeIntroducerAsClass); + break; + } + case TokenKind::Constraint: { + context.PushState(ParserState::TypeIntroducerAsNamedConstraint); + break; + } + case TokenKind::Fn: { + context.PushState(ParserState::FunctionIntroducer); + break; + } + case TokenKind::Interface: { + context.PushState(ParserState::TypeIntroducerAsInterface); + break; + } + case TokenKind::Semi: { + context.AddLeafNode(ParseNodeKind::EmptyDeclaration, context.Consume()); + break; + } + case TokenKind::Var: { + context.PushState(ParserState::VarAsSemicolon); + break; + } + default: { + ParserHandleUnrecognizedDeclaration(context); + break; + } + } +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_designator.cpp b/toolchain/parser/parser_handle_designator.cpp new file mode 100644 index 0000000000000..7ec648157e643 --- /dev/null +++ b/toolchain/parser/parser_handle_designator.cpp @@ -0,0 +1,49 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles DesignatorAs. +auto ParserHandleDesignator(ParserContext& context, bool as_struct) -> void { + auto state = context.PopState(); + + // `.` identifier + auto dot = context.ConsumeChecked(TokenKind::Period); + + if (!context.ConsumeAndAddLeafNodeIf(TokenKind::Identifier, + ParseNodeKind::DesignatedName)) { + CARBON_DIAGNOSTIC(ExpectedIdentifierAfterDot, Error, + "Expected identifier after `.`."); + context.emitter().Emit(*context.position(), ExpectedIdentifierAfterDot); + // If we see a keyword, assume it was intended to be the designated name. + // TODO: Should keywords be valid in designators? + if (context.PositionKind().is_keyword()) { + context.AddLeafNode(ParseNodeKind::DesignatedName, context.Consume(), + /*has_error=*/true); + } else { + context.AddLeafNode(ParseNodeKind::DesignatedName, *context.position(), + /*has_error=*/true); + // Indicate the error to the parent state so that it can avoid producing + // more errors. + context.ReturnErrorOnState(); + } + } + + context.AddNode(as_struct ? ParseNodeKind::StructFieldDesignator + : ParseNodeKind::DesignatorExpression, + dot, state.subtree_start, state.has_error); +} + +auto ParserHandleDesignatorAsExpression(ParserContext& context) -> void { + ParserHandleDesignator(context, /*as_struct=*/false); +} + +auto ParserHandleDesignatorAsStruct(ParserContext& context) -> void { + ParserHandleDesignator(context, /*as_struct=*/true); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_expression.cpp b/toolchain/parser/parser_handle_expression.cpp new file mode 100644 index 0000000000000..84f5664e00162 --- /dev/null +++ b/toolchain/parser/parser_handle_expression.cpp @@ -0,0 +1,227 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleExpression(ParserContext& context) -> void { + auto state = context.PopState(); + + // Check for a prefix operator. + if (auto operator_precedence = + PrecedenceGroup::ForLeading(context.PositionKind())) { + if (PrecedenceGroup::GetPriority(state.ambient_precedence, + *operator_precedence) != + OperatorPriority::RightFirst) { + // The precedence rules don't permit this prefix operator in this + // context. Diagnose this, but carry on and parse it anyway. + context.emitter().Emit(*context.position(), OperatorRequiresParentheses); + } else { + // Check that this operator follows the proper whitespace rules. + context.DiagnoseOperatorFixity(ParserContext::OperatorFixity::Prefix); + } + + context.PushStateForExpressionLoop(ParserState::ExpressionLoopForPrefix, + state.ambient_precedence, + *operator_precedence); + ++context.position(); + context.PushStateForExpression(*operator_precedence); + } else { + context.PushStateForExpressionLoop(ParserState::ExpressionLoop, + state.ambient_precedence, + PrecedenceGroup::ForPostfixExpression()); + context.PushState(ParserState::ExpressionInPostfix); + } +} + +auto ParserHandleExpressionInPostfix(ParserContext& context) -> void { + auto state = context.PopState(); + + // Continue to the loop state. + state.state = ParserState::ExpressionInPostfixLoop; + + // Parses a primary expression, which is either a terminal portion of an + // expression tree, such as an identifier or literal, or a parenthesized + // expression. + switch (context.PositionKind()) { + case TokenKind::Identifier: { + context.AddLeafNode(ParseNodeKind::NameReference, context.Consume()); + context.PushState(state); + break; + } + case TokenKind::IntegerLiteral: + case TokenKind::RealLiteral: + case TokenKind::StringLiteral: + case TokenKind::IntegerTypeLiteral: + case TokenKind::UnsignedIntegerTypeLiteral: + case TokenKind::FloatingPointTypeLiteral: + case TokenKind::StringTypeLiteral: { + context.AddLeafNode(ParseNodeKind::Literal, context.Consume()); + context.PushState(state); + break; + } + case TokenKind::OpenCurlyBrace: { + context.PushState(state); + context.PushState(ParserState::BraceExpression); + break; + } + case TokenKind::OpenParen: { + context.PushState(state); + context.PushState(ParserState::ParenExpression); + break; + } + case TokenKind::SelfValueIdentifier: { + context.AddLeafNode(ParseNodeKind::SelfValueIdentifier, + context.Consume()); + context.PushState(state); + break; + } + case TokenKind::SelfTypeIdentifier: { + context.AddLeafNode(ParseNodeKind::SelfTypeIdentifier, context.Consume()); + context.PushState(state); + break; + } + default: { + // Add a node to keep the parse tree balanced. + context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(), + /*has_error=*/true); + CARBON_DIAGNOSTIC(ExpectedExpression, Error, "Expected expression."); + context.emitter().Emit(*context.position(), ExpectedExpression); + context.ReturnErrorOnState(); + break; + } + } +} + +auto ParserHandleExpressionInPostfixLoop(ParserContext& context) -> void { + // This is a cyclic state that repeats, so this state is typically pushed back + // on. + auto state = context.PopState(); + + state.token = *context.position(); + + switch (context.PositionKind()) { + case TokenKind::Period: { + context.PushState(state); + state.state = ParserState::DesignatorAsExpression; + context.PushState(state); + break; + } + case TokenKind::OpenParen: { + context.PushState(state); + state.state = ParserState::CallExpression; + context.PushState(state); + break; + } + default: { + if (state.has_error) { + context.ReturnErrorOnState(); + } + break; + } + } +} + +auto ParserHandleExpressionLoop(ParserContext& context) -> void { + auto state = context.PopState(); + + auto trailing_operator = PrecedenceGroup::ForTrailing( + context.PositionKind(), context.IsTrailingOperatorInfix()); + if (!trailing_operator) { + if (state.has_error) { + context.ReturnErrorOnState(); + } + return; + } + auto [operator_precedence, is_binary] = *trailing_operator; + + // TODO: If this operator is ambiguous with either the ambient precedence + // or the LHS precedence, and there's a variant with a different fixity + // that would work, use that one instead for error recovery. + if (PrecedenceGroup::GetPriority(state.ambient_precedence, + operator_precedence) != + OperatorPriority::RightFirst) { + // The precedence rules don't permit this operator in this context. Try + // again in the enclosing expression context. + if (state.has_error) { + context.ReturnErrorOnState(); + } + return; + } + + if (PrecedenceGroup::GetPriority(state.lhs_precedence, operator_precedence) != + OperatorPriority::LeftFirst) { + // Either the LHS operator and this operator are ambiguous, or the + // LHS operator is a unary operator that can't be nested within + // this operator. Either way, parentheses are required. + context.emitter().Emit(*context.position(), OperatorRequiresParentheses); + state.has_error = true; + } else { + context.DiagnoseOperatorFixity( + is_binary ? ParserContext::OperatorFixity::Infix + : ParserContext::OperatorFixity::Postfix); + } + + state.token = context.Consume(); + state.lhs_precedence = operator_precedence; + + if (is_binary) { + state.state = ParserState::ExpressionLoopForBinary; + context.PushState(state); + context.PushStateForExpression(operator_precedence); + } else { + context.AddNode(ParseNodeKind::PostfixOperator, state.token, + state.subtree_start, state.has_error); + state.has_error = false; + context.PushState(state); + } +} + +auto ParserHandleExpressionLoopForBinary(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::InfixOperator, state.token, + state.subtree_start, state.has_error); + state.state = ParserState::ExpressionLoop; + state.has_error = false; + context.PushState(state); +} + +auto ParserHandleExpressionLoopForPrefix(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::PrefixOperator, state.token, + state.subtree_start, state.has_error); + state.state = ParserState::ExpressionLoop; + state.has_error = false; + context.PushState(state); +} + +auto ParserHandleExpressionStatementFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + if (auto semi = context.ConsumeIf(TokenKind::Semi)) { + context.AddNode(ParseNodeKind::ExpressionStatement, *semi, + state.subtree_start, state.has_error); + return; + } + + if (!state.has_error) { + context.emitter().Emit(*context.position(), ExpectedSemiAfterExpression); + } + + if (auto semi_token = context.SkipPastLikelyEnd(state.token)) { + context.AddNode(ParseNodeKind::ExpressionStatement, *semi_token, + state.subtree_start, + /*has_error=*/true); + return; + } + + // Found junk not even followed by a `;`, no node to add. + context.ReturnErrorOnState(); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_function.cpp b/toolchain/parser/parser_handle_function.cpp new file mode 100644 index 0000000000000..e8c1dc38edb72 --- /dev/null +++ b/toolchain/parser/parser_handle_function.cpp @@ -0,0 +1,99 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleFunctionIntroducer(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddLeafNode(ParseNodeKind::FunctionIntroducer, context.Consume()); + + state.state = ParserState::FunctionAfterParameters; + context.PushState(state); + state.state = ParserState::DeclarationNameAndParamsAsRequired; + context.PushState(state); +} + +auto ParserHandleFunctionAfterParameters(ParserContext& context) -> void { + auto state = context.PopState(); + + // Regardless of whether there's a return type, we'll finish the signature. + state.state = ParserState::FunctionSignatureFinish; + context.PushState(state); + + // If there is a return type, parse the expression before adding the return + // type nod.e + if (context.PositionIs(TokenKind::MinusGreater)) { + context.PushState(ParserState::FunctionReturnTypeFinish); + ++context.position(); + context.PushStateForExpression(PrecedenceGroup::ForType()); + } +} + +auto ParserHandleFunctionReturnTypeFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::ReturnType, state.token, state.subtree_start, + state.has_error); +} + +auto ParserHandleFunctionSignatureFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + switch (context.PositionKind()) { + case TokenKind::Semi: { + context.AddNode(ParseNodeKind::FunctionDeclaration, context.Consume(), + state.subtree_start, state.has_error); + break; + } + case TokenKind::OpenCurlyBrace: { + if (auto decl_context = context.GetDeclarationContext(); + decl_context == ParserContext::DeclarationContext::Interface || + decl_context == ParserContext::DeclarationContext::NamedConstraint) { + CARBON_DIAGNOSTIC( + MethodImplNotAllowed, Error, + "Method implementations are not allowed in interfaces."); + context.emitter().Emit(*context.position(), MethodImplNotAllowed); + context.RecoverFromDeclarationError(state, + ParseNodeKind::FunctionDeclaration, + /*skip_past_likely_end=*/true); + break; + } + + context.AddNode(ParseNodeKind::FunctionDefinitionStart, context.Consume(), + state.subtree_start, state.has_error); + // Any error is recorded on the FunctionDefinitionStart. + state.has_error = false; + state.state = ParserState::FunctionDefinitionFinish; + context.PushState(state); + context.PushState(ParserState::StatementScopeLoop); + break; + } + default: { + if (!state.has_error) { + context.emitter().Emit(*context.position(), + ExpectedDeclarationSemiOrDefinition, + TokenKind::Fn); + } + // Only need to skip if we've not already found a new line. + bool skip_past_likely_end = + context.tokens().GetLine(*context.position()) == + context.tokens().GetLine(state.token); + context.RecoverFromDeclarationError( + state, ParseNodeKind::FunctionDeclaration, skip_past_likely_end); + break; + } + } +} + +auto ParserHandleFunctionDefinitionFinish(ParserContext& context) -> void { + auto state = context.PopState(); + context.AddNode(ParseNodeKind::FunctionDefinition, context.Consume(), + state.subtree_start, state.has_error); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_package.cpp b/toolchain/parser/parser_handle_package.cpp new file mode 100644 index 0000000000000..c869eaa342bbc --- /dev/null +++ b/toolchain/parser/parser_handle_package.cpp @@ -0,0 +1,94 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandlePackage(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddLeafNode(ParseNodeKind::PackageIntroducer, context.Consume()); + + auto exit_on_parse_error = [&]() { + auto semi_token = context.SkipPastLikelyEnd(state.token); + return context.AddNode(ParseNodeKind::PackageDirective, + semi_token ? *semi_token : state.token, + state.subtree_start, + /*has_error=*/true); + }; + + if (!context.ConsumeAndAddLeafNodeIf(TokenKind::Identifier, + ParseNodeKind::DeclaredName)) { + CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPackage, Error, + "Expected identifier after `package`."); + context.emitter().Emit(*context.position(), ExpectedIdentifierAfterPackage); + exit_on_parse_error(); + return; + } + + bool library_parsed = false; + if (auto library_token = context.ConsumeIf(TokenKind::Library)) { + auto library_start = context.tree().size(); + + if (!context.ConsumeAndAddLeafNodeIf(TokenKind::StringLiteral, + ParseNodeKind::Literal)) { + CARBON_DIAGNOSTIC( + ExpectedLibraryName, Error, + "Expected a string literal to specify the library name."); + context.emitter().Emit(*context.position(), ExpectedLibraryName); + exit_on_parse_error(); + return; + } + + context.AddNode(ParseNodeKind::PackageLibrary, *library_token, + library_start, + /*has_error=*/false); + library_parsed = true; + } + + switch (auto api_or_impl_token = + context.tokens().GetKind(*(context.position()))) { + case TokenKind::Api: { + context.AddLeafNode(ParseNodeKind::PackageApi, context.Consume()); + break; + } + case TokenKind::Impl: { + context.AddLeafNode(ParseNodeKind::PackageImpl, context.Consume()); + break; + } + default: { + if (!library_parsed && api_or_impl_token == TokenKind::StringLiteral) { + // If we come acroess a string literal and we didn't parse `library + // "..."` yet, then most probably the user forgot to add `library` + // before the library name. + CARBON_DIAGNOSTIC(MissingLibraryKeyword, Error, + "Missing `library` keyword."); + context.emitter().Emit(*context.position(), MissingLibraryKeyword); + } else { + CARBON_DIAGNOSTIC(ExpectedApiOrImpl, Error, + "Expected a `api` or `impl`."); + context.emitter().Emit(*context.position(), ExpectedApiOrImpl); + } + exit_on_parse_error(); + return; + } + } + + if (!context.PositionIs(TokenKind::Semi)) { + CARBON_DIAGNOSTIC(ExpectedSemiToEndPackageDirective, Error, + "Expected `;` to end package directive."); + context.emitter().Emit(*context.position(), + ExpectedSemiToEndPackageDirective); + exit_on_parse_error(); + return; + } + + context.AddNode(ParseNodeKind::PackageDirective, context.Consume(), + state.subtree_start, + /*has_error=*/false); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_parameter.cpp b/toolchain/parser/parser_handle_parameter.cpp new file mode 100644 index 0000000000000..22b723e6a7431 --- /dev/null +++ b/toolchain/parser/parser_handle_parameter.cpp @@ -0,0 +1,109 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles ParameterAs(Deduced|Regular). +static auto ParserHandleParameter(ParserContext& context, + ParserState pattern_state, + ParserState finish_state) -> void { + context.PopAndDiscardState(); + + context.PushState(finish_state); + context.PushState(pattern_state); +} + +auto ParserHandleParameterAsDeduced(ParserContext& context) -> void { + ParserHandleParameter(context, ParserState::PatternAsDeducedParameter, + ParserState::ParameterFinishAsDeduced); +} + +auto ParserHandleParameterAsRegular(ParserContext& context) -> void { + ParserHandleParameter(context, ParserState::PatternAsParameter, + ParserState::ParameterFinishAsRegular); +} + +// Handles ParameterFinishAs(Deduced|Regular). +static auto ParserHandleParameterFinish(ParserContext& context, + TokenKind close_token, + ParserState param_state) -> void { + auto state = context.PopState(); + + if (state.has_error) { + context.ReturnErrorOnState(); + } + + if (context.ConsumeListToken(ParseNodeKind::ParameterListComma, close_token, + state.has_error) == + ParserContext::ListTokenKind::Comma) { + context.PushState(param_state); + } +} + +auto ParserHandleParameterFinishAsDeduced(ParserContext& context) -> void { + ParserHandleParameterFinish(context, TokenKind::CloseSquareBracket, + ParserState::ParameterAsDeduced); +} + +auto ParserHandleParameterFinishAsRegular(ParserContext& context) -> void { + ParserHandleParameterFinish(context, TokenKind::CloseParen, + ParserState::ParameterAsRegular); +} + +// Handles ParameterListAs(Deduced|Regular). +static auto ParserHandleParameterList(ParserContext& context, + ParseNodeKind parse_node_kind, + TokenKind open_token_kind, + TokenKind close_token_kind, + ParserState param_state, + ParserState finish_state) -> void { + context.PopAndDiscardState(); + + context.PushState(finish_state); + context.AddLeafNode(parse_node_kind, context.ConsumeChecked(open_token_kind)); + + if (!context.PositionIs(close_token_kind)) { + context.PushState(param_state); + } +} + +auto ParserHandleParameterListAsDeduced(ParserContext& context) -> void { + ParserHandleParameterList(context, ParseNodeKind::DeducedParameterListStart, + TokenKind::OpenSquareBracket, + TokenKind::CloseSquareBracket, + ParserState::ParameterAsDeduced, + ParserState::ParameterListFinishAsDeduced); +} + +auto ParserHandleParameterListAsRegular(ParserContext& context) -> void { + ParserHandleParameterList(context, ParseNodeKind::ParameterListStart, + TokenKind::OpenParen, TokenKind::CloseParen, + ParserState::ParameterAsRegular, + ParserState::ParameterListFinishAsRegular); +} + +// Handles ParameterListFinishAs(Deduced|Regular). +static auto ParserHandleParameterListFinish(ParserContext& context, + ParseNodeKind parse_node_kind, + TokenKind token_kind) -> void { + auto state = context.PopState(); + + context.AddNode(parse_node_kind, context.ConsumeChecked(token_kind), + state.subtree_start, state.has_error); +} + +auto ParserHandleParameterListFinishAsDeduced(ParserContext& context) -> void { + ParserHandleParameterListFinish(context, ParseNodeKind::DeducedParameterList, + TokenKind::CloseSquareBracket); +} + +auto ParserHandleParameterListFinishAsRegular(ParserContext& context) -> void { + ParserHandleParameterListFinish(context, ParseNodeKind::ParameterList, + TokenKind::CloseParen); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_paren_condition.cpp b/toolchain/parser/parser_handle_paren_condition.cpp new file mode 100644 index 0000000000000..683fee641e618 --- /dev/null +++ b/toolchain/parser/parser_handle_paren_condition.cpp @@ -0,0 +1,45 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles ParenConditionAs(If|While). +static auto ParserHandleParenCondition(ParserContext& context, + ParseNodeKind start_kind, + ParserState finish_state) -> void { + auto state = context.PopState(); + + context.ConsumeAndAddOpenParen(state.token, start_kind); + + state.state = finish_state; + context.PushState(state); + context.PushState(ParserState::Expression); +} + +auto ParserHandleParenConditionAsIf(ParserContext& context) -> void { + ParserHandleParenCondition(context, ParseNodeKind::IfConditionStart, + ParserState::ParenConditionFinishAsIf); +} + +auto ParserHandleParenConditionAsWhile(ParserContext& context) -> void { + ParserHandleParenCondition(context, ParseNodeKind::WhileConditionStart, + ParserState::ParenConditionFinishAsWhile); +} + +auto ParserHandleParenConditionFinishAsIf(ParserContext& context) -> void { + auto state = context.PopState(); + + context.ConsumeAndAddCloseParen(state, ParseNodeKind::IfCondition); +} + +auto ParserHandleParenConditionFinishAsWhile(ParserContext& context) -> void { + auto state = context.PopState(); + + context.ConsumeAndAddCloseParen(state, ParseNodeKind::WhileCondition); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_paren_expression.cpp b/toolchain/parser/parser_handle_paren_expression.cpp new file mode 100644 index 0000000000000..d46c2a109fc7b --- /dev/null +++ b/toolchain/parser/parser_handle_paren_expression.cpp @@ -0,0 +1,84 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleParenExpression(ParserContext& context) -> void { + auto state = context.PopState(); + + // Advance past the open paren. + context.AddLeafNode(ParseNodeKind::ParenExpressionOrTupleLiteralStart, + context.ConsumeChecked(TokenKind::OpenParen)); + + if (context.PositionIs(TokenKind::CloseParen)) { + state.state = ParserState::ParenExpressionFinishAsTuple; + context.PushState(state); + } else { + state.state = ParserState::ParenExpressionFinishAsNormal; + context.PushState(state); + context.PushState(ParserState::ParenExpressionParameterFinishAsUnknown); + context.PushState(ParserState::Expression); + } +} + +// Handles ParenExpressionParameterFinishAs(Unknown|Tuple). +static auto ParserHandleParenExpressionParameterFinish(ParserContext& context, + bool as_tuple) -> void { + auto state = context.PopState(); + + auto list_token_kind = context.ConsumeListToken( + ParseNodeKind::TupleLiteralComma, TokenKind::CloseParen, state.has_error); + if (list_token_kind == ParserContext::ListTokenKind::Close) { + return; + } + + // If this is the first item and a comma was found, switch to tuple handling. + // Note this could be `(expr,)` so we may not reuse the current state, but + // it's still necessary to switch the parent. + if (!as_tuple) { + state.state = ParserState::ParenExpressionParameterFinishAsTuple; + + auto finish_state = context.PopState(); + CARBON_CHECK(finish_state.state == + ParserState::ParenExpressionFinishAsNormal) + << "Unexpected parent state, found: " << finish_state.state; + finish_state.state = ParserState::ParenExpressionFinishAsTuple; + context.PushState(finish_state); + } + + // On a comma, push another expression handler. + if (list_token_kind == ParserContext::ListTokenKind::Comma) { + context.PushState(state); + context.PushState(ParserState::Expression); + } +} + +auto ParserHandleParenExpressionParameterFinishAsUnknown(ParserContext& context) + -> void { + ParserHandleParenExpressionParameterFinish(context, /*as_tuple=*/false); +} + +auto ParserHandleParenExpressionParameterFinishAsTuple(ParserContext& context) + -> void { + ParserHandleParenExpressionParameterFinish(context, /*as_tuple=*/true); +} + +auto ParserHandleParenExpressionFinishAsNormal(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::ParenExpression, context.Consume(), + state.subtree_start, state.has_error); +} + +auto ParserHandleParenExpressionFinishAsTuple(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::TupleLiteral, context.Consume(), + state.subtree_start, state.has_error); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_pattern.cpp b/toolchain/parser/parser_handle_pattern.cpp new file mode 100644 index 0000000000000..3d0bce3afd2cd --- /dev/null +++ b/toolchain/parser/parser_handle_pattern.cpp @@ -0,0 +1,142 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles PatternAs(DeducedParameter|FunctionParameter|Variable). +static auto ParserHandlePattern(ParserContext& context, + ParserContext::PatternKind pattern_kind) + -> void { + auto state = context.PopState(); + + // Parameters may have keywords prefixing the pattern. They become the parent + // for the full PatternBinding. + if (pattern_kind != ParserContext::PatternKind::Variable) { + context.ConsumeIfPatternKeyword( + TokenKind::Template, ParserState::PatternTemplate, state.subtree_start); + context.ConsumeIfPatternKeyword( + TokenKind::Addr, ParserState::PatternAddress, state.subtree_start); + } + + // ParserHandle an invalid pattern introducer for parameters and variables. + auto on_error = [&]() { + switch (pattern_kind) { + case ParserContext::PatternKind::DeducedParameter: + case ParserContext::PatternKind::Parameter: { + CARBON_DIAGNOSTIC(ExpectedParameterName, Error, + "Expected parameter declaration."); + context.emitter().Emit(*context.position(), ExpectedParameterName); + break; + } + case ParserContext::PatternKind::Variable: { + CARBON_DIAGNOSTIC(ExpectedVariableName, Error, + "Expected pattern in `var` declaration."); + context.emitter().Emit(*context.position(), ExpectedVariableName); + break; + } + } + // Add a placeholder for the type. + context.AddLeafNode(ParseNodeKind::InvalidParse, *context.position(), + /*has_error=*/true); + state.state = ParserState::PatternFinishAsRegular; + state.has_error = true; + context.PushState(state); + }; + + // The first item should be an identifier or, for deduced parameters, `self`. + bool has_name = false; + if (auto identifier = context.ConsumeIf(TokenKind::Identifier)) { + context.AddLeafNode(ParseNodeKind::DeclaredName, *identifier); + has_name = true; + } else if (pattern_kind == ParserContext::PatternKind::DeducedParameter) { + if (auto self = context.ConsumeIf(TokenKind::SelfValueIdentifier)) { + context.AddLeafNode(ParseNodeKind::SelfValueIdentifier, *self); + has_name = true; + } + } + if (!has_name) { + // Add a placeholder for the name. + context.AddLeafNode(ParseNodeKind::DeclaredName, *context.position(), + /*has_error=*/true); + on_error(); + return; + } + + if (auto kind = context.PositionKind(); + kind == TokenKind::Colon || kind == TokenKind::ColonExclaim) { + state.state = kind == TokenKind::Colon + ? ParserState::PatternFinishAsRegular + : ParserState::PatternFinishAsGeneric; + // Use the `:` or `:!` for the root node. + state.token = context.Consume(); + context.PushState(state); + context.PushStateForExpression(PrecedenceGroup::ForType()); + } else { + on_error(); + return; + } +} + +auto ParserHandlePatternAsDeducedParameter(ParserContext& context) -> void { + ParserHandlePattern(context, ParserContext::PatternKind::DeducedParameter); +} + +auto ParserHandlePatternAsParameter(ParserContext& context) -> void { + ParserHandlePattern(context, ParserContext::PatternKind::Parameter); +} + +auto ParserHandlePatternAsVariable(ParserContext& context) -> void { + ParserHandlePattern(context, ParserContext::PatternKind::Variable); +} + +// Handles PatternFinishAs(Generic|Regular). +static auto ParserHandlePatternFinish(ParserContext& context, + ParseNodeKind node_kind) -> void { + auto state = context.PopState(); + + context.AddNode(node_kind, state.token, state.subtree_start, state.has_error); + + // Propagate errors to the parent state so that they can take different + // actions on invalid patterns. + if (state.has_error) { + context.ReturnErrorOnState(); + } +} + +auto ParserHandlePatternFinishAsGeneric(ParserContext& context) -> void { + ParserHandlePatternFinish(context, ParseNodeKind::GenericPatternBinding); +} + +auto ParserHandlePatternFinishAsRegular(ParserContext& context) -> void { + ParserHandlePatternFinish(context, ParseNodeKind::PatternBinding); +} + +auto ParserHandlePatternAddress(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::Address, state.token, state.subtree_start, + state.has_error); + + // If an error was encountered, propagate it while adding a node. + if (state.has_error) { + context.ReturnErrorOnState(); + } +} + +auto ParserHandlePatternTemplate(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::Template, state.token, state.subtree_start, + state.has_error); + + // If an error was encountered, propagate it while adding a node. + if (state.has_error) { + context.ReturnErrorOnState(); + } +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_statement.cpp b/toolchain/parser/parser_handle_statement.cpp new file mode 100644 index 0000000000000..c9758e3918511 --- /dev/null +++ b/toolchain/parser/parser_handle_statement.cpp @@ -0,0 +1,225 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +auto ParserHandleStatement(ParserContext& context) -> void { + context.PopAndDiscardState(); + + switch (context.PositionKind()) { + case TokenKind::Break: { + context.PushState(ParserState::StatementBreakFinish); + context.AddLeafNode(ParseNodeKind::BreakStatementStart, + context.Consume()); + break; + } + case TokenKind::Continue: { + context.PushState(ParserState::StatementContinueFinish); + context.AddLeafNode(ParseNodeKind::ContinueStatementStart, + context.Consume()); + break; + } + case TokenKind::For: { + context.PushState(ParserState::StatementForFinish); + context.PushState(ParserState::StatementForHeader); + ++context.position(); + break; + } + case TokenKind::If: { + context.PushState(ParserState::StatementIf); + break; + } + case TokenKind::Return: { + context.PushState(ParserState::StatementReturn); + break; + } + case TokenKind::Var: { + context.PushState(ParserState::VarAsSemicolon); + break; + } + case TokenKind::While: { + context.PushState(ParserState::StatementWhile); + break; + } + default: { + context.PushState(ParserState::ExpressionStatementFinish); + context.PushState(ParserState::Expression); + break; + } + } +} + +// Handles the `;` after a keyword statement. +static auto ParserHandleStatementKeywordFinish(ParserContext& context, + ParseNodeKind node_kind) + -> void { + auto state = context.PopState(); + + auto semi = context.ConsumeIf(TokenKind::Semi); + if (!semi) { + CARBON_DIAGNOSTIC(ExpectedSemiAfter, Error, "Expected `;` after `{0}`.", + TokenKind); + context.emitter().Emit(*context.position(), ExpectedSemiAfter, + context.tokens().GetKind(state.token)); + state.has_error = true; + // Recover to the next semicolon if possible, otherwise indicate the + // keyword for the error. + semi = context.SkipPastLikelyEnd(state.token); + if (!semi) { + semi = state.token; + } + } + context.AddNode(node_kind, *semi, state.subtree_start, state.has_error); +} + +auto ParserHandleStatementBreakFinish(ParserContext& context) -> void { + ParserHandleStatementKeywordFinish(context, ParseNodeKind::BreakStatement); +} + +auto ParserHandleStatementContinueFinish(ParserContext& context) -> void { + ParserHandleStatementKeywordFinish(context, ParseNodeKind::ContinueStatement); +} + +auto ParserHandleStatementForHeader(ParserContext& context) -> void { + auto state = context.PopState(); + + context.ConsumeAndAddOpenParen(state.token, ParseNodeKind::ForHeaderStart); + + state.state = ParserState::StatementForHeaderIn; + + if (context.PositionIs(TokenKind::Var)) { + context.PushState(state); + context.PushState(ParserState::VarAsFor); + } else { + CARBON_DIAGNOSTIC(ExpectedVariableDeclaration, Error, + "Expected `var` declaration."); + context.emitter().Emit(*context.position(), ExpectedVariableDeclaration); + + if (auto next_in = context.FindNextOf({TokenKind::In})) { + context.SkipTo(*next_in); + ++context.position(); + } + state.has_error = true; + context.PushState(state); + } +} + +auto ParserHandleStatementForHeaderIn(ParserContext& context) -> void { + auto state = context.PopState(); + + state.state = ParserState::StatementForHeaderFinish; + context.PushState(state); + context.PushState(ParserState::Expression); +} + +auto ParserHandleStatementForHeaderFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + context.ConsumeAndAddCloseParen(state, ParseNodeKind::ForHeader); + + context.PushState(ParserState::CodeBlock); +} + +auto ParserHandleStatementForFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::ForStatement, state.token, state.subtree_start, + state.has_error); +} + +auto ParserHandleStatementIf(ParserContext& context) -> void { + context.PopAndDiscardState(); + + context.PushState(ParserState::StatementIfConditionFinish); + context.PushState(ParserState::ParenConditionAsIf); + ++context.position(); +} + +auto ParserHandleStatementIfConditionFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + state.state = ParserState::StatementIfThenBlockFinish; + context.PushState(state); + context.PushState(ParserState::CodeBlock); +} + +auto ParserHandleStatementIfThenBlockFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + if (context.ConsumeAndAddLeafNodeIf(TokenKind::Else, + ParseNodeKind::IfStatementElse)) { + state.state = ParserState::StatementIfElseBlockFinish; + context.PushState(state); + // `else if` is permitted as a special case. + context.PushState(context.PositionIs(TokenKind::If) + ? ParserState::StatementIf + : ParserState::CodeBlock); + } else { + context.AddNode(ParseNodeKind::IfStatement, state.token, + state.subtree_start, state.has_error); + } +} + +auto ParserHandleStatementIfElseBlockFinish(ParserContext& context) -> void { + auto state = context.PopState(); + context.AddNode(ParseNodeKind::IfStatement, state.token, state.subtree_start, + state.has_error); +} + +auto ParserHandleStatementReturn(ParserContext& context) -> void { + auto state = context.PopState(); + state.state = ParserState::StatementReturnFinish; + context.PushState(state); + + context.AddLeafNode(ParseNodeKind::ReturnStatementStart, context.Consume()); + if (!context.PositionIs(TokenKind::Semi)) { + context.PushState(ParserState::Expression); + } +} + +auto ParserHandleStatementReturnFinish(ParserContext& context) -> void { + ParserHandleStatementKeywordFinish(context, ParseNodeKind::ReturnStatement); +} + +auto ParserHandleStatementScopeLoop(ParserContext& context) -> void { + // This maintains the current state until we're at the end of the scope. + + auto token_kind = context.PositionKind(); + if (token_kind == TokenKind::CloseCurlyBrace) { + auto state = context.PopState(); + if (state.has_error) { + context.ReturnErrorOnState(); + } + } else { + context.PushState(ParserState::Statement); + } +} + +auto ParserHandleStatementWhile(ParserContext& context) -> void { + context.PopAndDiscardState(); + + context.PushState(ParserState::StatementWhileConditionFinish); + context.PushState(ParserState::ParenConditionAsWhile); + ++context.position(); +} + +auto ParserHandleStatementWhileConditionFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + state.state = ParserState::StatementWhileBlockFinish; + context.PushState(state); + context.PushState(ParserState::CodeBlock); +} + +auto ParserHandleStatementWhileBlockFinish(ParserContext& context) -> void { + auto state = context.PopState(); + + context.AddNode(ParseNodeKind::WhileStatement, state.token, + state.subtree_start, state.has_error); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_states.h b/toolchain/parser/parser_handle_states.h new file mode 100644 index 0000000000000..da11a56fe5bd4 --- /dev/null +++ b/toolchain/parser/parser_handle_states.h @@ -0,0 +1,20 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_PARSER_PARSER_HANDLE_STATES_H_ +#define CARBON_TOOLCHAIN_PARSER_PARSER_HANDLE_STATES_H_ + +#include "toolchain/parser/parser_context.h" + +namespace Carbon { + +// `clang-format` has a bug with spacing around `->` returns in macros. See +// https://bugs.llvm.org/show_bug.cgi?id=48320 for details. +#define CARBON_PARSER_STATE(Name) \ + auto ParserHandle##Name(ParserContext& context)->void; +#include "toolchain/parser/parser_state.def" + +} // namespace Carbon + +#endif // CARBON_TOOLCHAIN_PARSER_PARSER_HANDLE_STATES_H_ diff --git a/toolchain/parser/parser_handle_type.cpp b/toolchain/parser/parser_handle_type.cpp new file mode 100644 index 0000000000000..a1cedc0239fb8 --- /dev/null +++ b/toolchain/parser/parser_handle_type.cpp @@ -0,0 +1,122 @@ +// 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 "toolchain/parser/parser_context.h" +#include "toolchain/parser/parser_handle_states.h" + +namespace Carbon { + +// Handles processing of a type's introducer. +static auto ParserHandleTypeIntroducer(ParserContext& context, + ParseNodeKind introducer_kind, + ParserState after_params_state) -> void { + auto state = context.PopState(); + + context.AddLeafNode(introducer_kind, context.Consume()); + + state.state = after_params_state; + context.PushState(state); + state.state = ParserState::DeclarationNameAndParamsAsOptional; + context.PushState(state); +} + +auto ParserHandleTypeIntroducerAsClass(ParserContext& context) -> void { + ParserHandleTypeIntroducer(context, ParseNodeKind::ClassIntroducer, + ParserState::TypeAfterParamsAsClass); +} + +auto ParserHandleTypeIntroducerAsInterface(ParserContext& context) -> void { + ParserHandleTypeIntroducer(context, ParseNodeKind::InterfaceIntroducer, + ParserState::TypeAfterParamsAsInterface); +} + +auto ParserHandleTypeIntroducerAsNamedConstraint(ParserContext& context) + -> void { + ParserHandleTypeIntroducer(context, ParseNodeKind::NamedConstraintIntroducer, + ParserState::TypeAfterParamsAsNamedConstraint); +} + +// Handles processing after params, deciding whether it's a declaration or +// definition. +static auto ParserHandleTypeAfterParams(ParserContext& context, + ParseNodeKind declaration_kind, + ParseNodeKind definition_start_kind, + ParserState definition_finish_state) + -> void { + auto state = context.PopState(); + + if (state.has_error) { + context.RecoverFromDeclarationError(state, declaration_kind, + /*skip_past_likely_end=*/true); + return; + } + + if (auto semi = context.ConsumeIf(TokenKind::Semi)) { + context.AddNode(declaration_kind, *semi, state.subtree_start, + state.has_error); + return; + } + + if (!context.PositionIs(TokenKind::OpenCurlyBrace)) { + context.emitter().Emit(*context.position(), + ExpectedDeclarationSemiOrDefinition, + context.tokens().GetKind(state.token)); + context.RecoverFromDeclarationError(state, declaration_kind, + /*skip_past_likely_end=*/true); + return; + } + + state.state = definition_finish_state; + context.PushState(state); + context.PushState(ParserState::DeclarationScopeLoop); + context.AddNode(definition_start_kind, context.Consume(), state.subtree_start, + state.has_error); +} + +auto ParserHandleTypeAfterParamsAsClass(ParserContext& context) -> void { + ParserHandleTypeAfterParams(context, ParseNodeKind::ClassDeclaration, + ParseNodeKind::ClassDefinitionStart, + ParserState::TypeDefinitionFinishAsClass); +} + +auto ParserHandleTypeAfterParamsAsInterface(ParserContext& context) -> void { + ParserHandleTypeAfterParams(context, ParseNodeKind::InterfaceDeclaration, + ParseNodeKind::InterfaceDefinitionStart, + ParserState::TypeDefinitionFinishAsInterface); +} + +auto ParserHandleTypeAfterParamsAsNamedConstraint(ParserContext& context) + -> void { + ParserHandleTypeAfterParams( + context, ParseNodeKind::NamedConstraintDeclaration, + ParseNodeKind::NamedConstraintDefinitionStart, + ParserState::TypeDefinitionFinishAsNamedConstraint); +} + +// Handles parsing after the declaration scope of a type. +static auto ParserHandleTypeDefinitionFinish(ParserContext& context, + ParseNodeKind definition_kind) + -> void { + auto state = context.PopState(); + + context.AddNode(definition_kind, context.Consume(), state.subtree_start, + state.has_error); +} + +auto ParserHandleTypeDefinitionFinishAsClass(ParserContext& context) -> void { + ParserHandleTypeDefinitionFinish(context, ParseNodeKind::ClassDefinition); +} + +auto ParserHandleTypeDefinitionFinishAsInterface(ParserContext& context) + -> void { + ParserHandleTypeDefinitionFinish(context, ParseNodeKind::InterfaceDefinition); +} + +auto ParserHandleTypeDefinitionFinishAsNamedConstraint(ParserContext& context) + -> void { + ParserHandleTypeDefinitionFinish(context, + ParseNodeKind::NamedConstraintDefinition); +} + +} // namespace Carbon diff --git a/toolchain/parser/parser_handle_var.cpp b/toolchain/parser/parser_handle_var.cpp new file mode 100644 index 0000000000000..c1a0fc4fd88cc --- /dev/null +++ b/toolchain/parser/parser_handle_var.cpp @@ -0,0 +1,88 @@ +// 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 "toolchain/parser/parser_context.h" + +namespace Carbon { + +// Handles VarAs(Semicolon|For). +static auto ParserHandleVar(ParserContext& context, ParserState finish_state) + -> void { + context.PopAndDiscardState(); + + // These will start at the `var`. + context.PushState(finish_state); + context.PushState(ParserState::VarAfterPattern); + + context.AddLeafNode(ParseNodeKind::VariableIntroducer, context.Consume()); + + // This will start at the pattern. + context.PushState(ParserState::PatternAsVariable); +} + +auto ParserHandleVarAsSemicolon(ParserContext& context) -> void { + ParserHandleVar(context, ParserState::VarFinishAsSemicolon); +} + +auto ParserHandleVarAsFor(ParserContext& context) -> void { + ParserHandleVar(context, ParserState::VarFinishAsFor); +} + +auto ParserHandleVarAfterPattern(ParserContext& context) -> void { + auto state = context.PopState(); + + if (state.has_error) { + if (auto after_pattern = + context.FindNextOf({TokenKind::Equal, TokenKind::Semi})) { + context.SkipTo(*after_pattern); + } + } + + if (auto equals = context.ConsumeIf(TokenKind::Equal)) { + context.AddLeafNode(ParseNodeKind::VariableInitializer, *equals); + context.PushState(ParserState::Expression); + } +} + +auto ParserHandleVarFinishAsSemicolon(ParserContext& context) -> void { + auto state = context.PopState(); + + auto end_token = state.token; + if (context.PositionIs(TokenKind::Semi)) { + end_token = context.Consume(); + } else { + context.emitter().Emit(*context.position(), ExpectedSemiAfterExpression); + state.has_error = true; + if (auto semi_token = context.SkipPastLikelyEnd(state.token)) { + end_token = *semi_token; + } + } + context.AddNode(ParseNodeKind::VariableDeclaration, end_token, + state.subtree_start, state.has_error); +} + +auto ParserHandleVarFinishAsFor(ParserContext& context) -> void { + auto state = context.PopState(); + + auto end_token = state.token; + if (context.PositionIs(TokenKind::In)) { + end_token = context.Consume(); + } else if (context.PositionIs(TokenKind::Colon)) { + CARBON_DIAGNOSTIC(ExpectedInNotColon, Error, + "`:` should be replaced by `in`."); + context.emitter().Emit(*context.position(), ExpectedInNotColon); + state.has_error = true; + end_token = context.Consume(); + } else { + CARBON_DIAGNOSTIC(ExpectedIn, Error, + "Expected `in` after loop `var` declaration."); + context.emitter().Emit(*context.position(), ExpectedIn); + state.has_error = true; + } + + context.AddNode(ParseNodeKind::ForIn, end_token, state.subtree_start, + state.has_error); +} + +} // namespace Carbon From c4a2f9cfa8513b2bb6e919a442461b1b116aee7f Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 17:31:49 +0000 Subject: [PATCH 03/29] Fix pretty stack tracing --- toolchain/parser/parse_tree.cpp | 32 +++++++++++++++++++++++++++++ toolchain/parser/parser_context.cpp | 31 ---------------------------- toolchain/parser/parser_context.h | 3 --- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/toolchain/parser/parse_tree.cpp b/toolchain/parser/parse_tree.cpp index b6e6da731a284..60ddcf9fe1006 100644 --- a/toolchain/parser/parse_tree.cpp +++ b/toolchain/parser/parse_tree.cpp @@ -11,6 +11,7 @@ #include "common/error.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/PrettyStackTrace.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" #include "toolchain/parser/parser_context.h" @@ -18,6 +19,36 @@ namespace Carbon { +class PrettyStackTraceParserContext : public llvm::PrettyStackTraceEntry { + public: + explicit PrettyStackTraceParserContext(const ParserContext* context) + : context_(context) {} + ~PrettyStackTraceParserContext() override = default; + + auto print(llvm::raw_ostream& output) const -> void override { + output << "Parser stack:\n"; + for (int i = 0; i < static_cast(context_->state_stack().size()); ++i) { + const auto& entry = context_->state_stack()[i]; + output << "\t" << i << ".\t" << entry.state; + Print(output, entry.token); + } + output << "\tcursor\tposition_"; + Print(output, *context_->position()); + } + + private: + auto Print(llvm::raw_ostream& output, TokenizedBuffer::Token token) const + -> void { + auto line = context_->tokens().GetLine(token); + output << " @ " << context_->tokens().GetLineNumber(line) << ":" + << context_->tokens().GetColumnNumber(token) << ":" + << " token " << token << " : " << context_->tokens().GetKind(token) + << "\n"; + } + + const ParserContext* context_; +}; + auto ParseTree::Parse(TokenizedBuffer& tokens, DiagnosticConsumer& consumer, llvm::raw_ostream* vlog_stream) -> ParseTree { TokenizedBuffer::TokenLocationTranslator translator( @@ -27,6 +58,7 @@ auto ParseTree::Parse(TokenizedBuffer& tokens, DiagnosticConsumer& consumer, // Delegate to the parser. ParseTree tree(tokens); ParserContext context(tree, tokens, emitter, vlog_stream); + PrettyStackTraceParserContext pretty_context(&context); context.PushState(ParserState::DeclarationScopeLoop); diff --git a/toolchain/parser/parser_context.cpp b/toolchain/parser/parser_context.cpp index 00c9fabc2050f..f5064d178623c 100644 --- a/toolchain/parser/parser_context.cpp +++ b/toolchain/parser/parser_context.cpp @@ -9,7 +9,6 @@ #include #include "common/check.h" -#include "llvm/Support/PrettyStackTrace.h" #include "toolchain/lexer/token_kind.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" @@ -42,36 +41,6 @@ static auto operator<<(llvm::raw_ostream& out, RelativeLocation loc) return out; } -class PrettyStackTraceParseState : public llvm::PrettyStackTraceEntry { - public: - explicit PrettyStackTraceParseState(const ParserContext* context) - : context_(context) {} - ~PrettyStackTraceParseState() override = default; - - auto print(llvm::raw_ostream& output) const -> void override { - output << "Parser stack:\n"; - for (int i = 0; i < static_cast(context_->state_stack().size()); ++i) { - const auto& entry = context_->state_stack()[i]; - output << "\t" << i << ".\t" << entry.state; - Print(output, entry.token); - } - output << "\tcursor\tposition_"; - Print(output, *context_->position()); - } - - private: - auto Print(llvm::raw_ostream& output, TokenizedBuffer::Token token) const - -> void { - auto line = context_->tokens().GetLine(token); - output << " @ " << context_->tokens().GetLineNumber(line) << ":" - << context_->tokens().GetColumnNumber(token) << ":" - << " token " << token << " : " << context_->tokens().GetKind(token) - << "\n"; - } - - const ParserContext* context_; -}; - ParserContext::ParserContext(ParseTree& tree, TokenizedBuffer& tokens, TokenDiagnosticEmitter& emitter, llvm::raw_ostream* vlog_stream) diff --git a/toolchain/parser/parser_context.h b/toolchain/parser/parser_context.h index f0c746900d64f..653caa65971eb 100644 --- a/toolchain/parser/parser_context.h +++ b/toolchain/parser/parser_context.h @@ -39,9 +39,6 @@ class ParserContext { NamedConstraint, }; - // Helper class for tracing state_stack_ on crashes. - class PrettyStackTraceParseState; - // Used to track state on state_stack_. struct StateStackEntry { explicit StateStackEntry(ParserState state, From bc9de0d4580eb3e148534863ce599699cc9930d2 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 17:36:40 +0000 Subject: [PATCH 04/29] Remove handle_states.h --- toolchain/parser/BUILD | 1 - toolchain/parser/parse_tree.cpp | 1 - toolchain/parser/parser_context.cpp | 1 - toolchain/parser/parser_context.h | 10 +++++----- .../parser/parser_handle_brace_expression.cpp | 1 - .../parser/parser_handle_call_expression.cpp | 1 - toolchain/parser/parser_handle_code_block.cpp | 1 - ...ser_handle_declaration_name_and_params.cpp | 1 - .../parser_handle_declaration_scope_loop.cpp | 1 - toolchain/parser/parser_handle_designator.cpp | 1 - toolchain/parser/parser_handle_expression.cpp | 1 - toolchain/parser/parser_handle_function.cpp | 1 - toolchain/parser/parser_handle_package.cpp | 1 - toolchain/parser/parser_handle_parameter.cpp | 1 - .../parser/parser_handle_paren_condition.cpp | 1 - .../parser/parser_handle_paren_expression.cpp | 1 - toolchain/parser/parser_handle_pattern.cpp | 1 - toolchain/parser/parser_handle_statement.cpp | 1 - toolchain/parser/parser_handle_states.h | 20 ------------------- toolchain/parser/parser_handle_type.cpp | 1 - 20 files changed, 5 insertions(+), 43 deletions(-) delete mode 100644 toolchain/parser/parser_handle_states.h diff --git a/toolchain/parser/BUILD b/toolchain/parser/BUILD index e3582d5feaa7f..4b20716ca03f7 100644 --- a/toolchain/parser/BUILD +++ b/toolchain/parser/BUILD @@ -45,7 +45,6 @@ cc_library( "parser_handle_paren_expression.cpp", "parser_handle_pattern.cpp", "parser_handle_statement.cpp", - "parser_handle_states.h", "parser_handle_type.cpp", "parser_handle_var.cpp", ], diff --git a/toolchain/parser/parse_tree.cpp b/toolchain/parser/parse_tree.cpp index 60ddcf9fe1006..721b2d65c195d 100644 --- a/toolchain/parser/parse_tree.cpp +++ b/toolchain/parser/parse_tree.cpp @@ -15,7 +15,6 @@ #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_context.cpp b/toolchain/parser/parser_context.cpp index f5064d178623c..117452bbffd48 100644 --- a/toolchain/parser/parser_context.cpp +++ b/toolchain/parser/parser_context.cpp @@ -13,7 +13,6 @@ #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/parser/parse_node_kind.h" #include "toolchain/parser/parse_tree.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_context.h b/toolchain/parser/parser_context.h index 653caa65971eb..fd1ff986192c6 100644 --- a/toolchain/parser/parser_context.h +++ b/toolchain/parser/parser_context.h @@ -296,11 +296,11 @@ class ParserContext { llvm::SmallVector state_stack_; }; -// Parses the tokens into a parse tree, emitting any errors encountered. -// -// This is the entry point to the parser implementation. -auto Parse(TokenizedBuffer& tokens, TokenDiagnosticEmitter& emitter, - llvm::raw_ostream* vlog_stream) -> ParseTree; +// `clang-format` has a bug with spacing around `->` returns in macros. See +// https://bugs.llvm.org/show_bug.cgi?id=48320 for details. +#define CARBON_PARSER_STATE(Name) \ + auto ParserHandle##Name(ParserContext& context)->void; +#include "toolchain/parser/parser_state.def" // The diagnostics below may be emitted a couple different ways as part of // operator parsing. diff --git a/toolchain/parser/parser_handle_brace_expression.cpp b/toolchain/parser/parser_handle_brace_expression.cpp index 6b54eb0e07ca7..f3761219ec08d 100644 --- a/toolchain/parser/parser_handle_brace_expression.cpp +++ b/toolchain/parser/parser_handle_brace_expression.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_call_expression.cpp b/toolchain/parser/parser_handle_call_expression.cpp index ca52b078766cc..976c85c31c6e1 100644 --- a/toolchain/parser/parser_handle_call_expression.cpp +++ b/toolchain/parser/parser_handle_call_expression.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_code_block.cpp b/toolchain/parser/parser_handle_code_block.cpp index 9b2c20b3b222d..df48807d00c1d 100644 --- a/toolchain/parser/parser_handle_code_block.cpp +++ b/toolchain/parser/parser_handle_code_block.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_declaration_name_and_params.cpp b/toolchain/parser/parser_handle_declaration_name_and_params.cpp index f12c2c384ee37..c75929b797099 100644 --- a/toolchain/parser/parser_handle_declaration_name_and_params.cpp +++ b/toolchain/parser/parser_handle_declaration_name_and_params.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_declaration_scope_loop.cpp b/toolchain/parser/parser_handle_declaration_scope_loop.cpp index 0ec8b253341e2..23a91de938b83 100644 --- a/toolchain/parser/parser_handle_declaration_scope_loop.cpp +++ b/toolchain/parser/parser_handle_declaration_scope_loop.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_designator.cpp b/toolchain/parser/parser_handle_designator.cpp index 7ec648157e643..857534405fc05 100644 --- a/toolchain/parser/parser_handle_designator.cpp +++ b/toolchain/parser/parser_handle_designator.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_expression.cpp b/toolchain/parser/parser_handle_expression.cpp index 84f5664e00162..8ee4b8ccba9a1 100644 --- a/toolchain/parser/parser_handle_expression.cpp +++ b/toolchain/parser/parser_handle_expression.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_function.cpp b/toolchain/parser/parser_handle_function.cpp index e8c1dc38edb72..bbc8944fc82f8 100644 --- a/toolchain/parser/parser_handle_function.cpp +++ b/toolchain/parser/parser_handle_function.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_package.cpp b/toolchain/parser/parser_handle_package.cpp index c869eaa342bbc..a1265069662b6 100644 --- a/toolchain/parser/parser_handle_package.cpp +++ b/toolchain/parser/parser_handle_package.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_parameter.cpp b/toolchain/parser/parser_handle_parameter.cpp index 22b723e6a7431..3eb1e6c7190eb 100644 --- a/toolchain/parser/parser_handle_parameter.cpp +++ b/toolchain/parser/parser_handle_parameter.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_paren_condition.cpp b/toolchain/parser/parser_handle_paren_condition.cpp index 683fee641e618..1802174c858be 100644 --- a/toolchain/parser/parser_handle_paren_condition.cpp +++ b/toolchain/parser/parser_handle_paren_condition.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_paren_expression.cpp b/toolchain/parser/parser_handle_paren_expression.cpp index d46c2a109fc7b..d6b21732c888e 100644 --- a/toolchain/parser/parser_handle_paren_expression.cpp +++ b/toolchain/parser/parser_handle_paren_expression.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_pattern.cpp b/toolchain/parser/parser_handle_pattern.cpp index 3d0bce3afd2cd..2252c9f487cf4 100644 --- a/toolchain/parser/parser_handle_pattern.cpp +++ b/toolchain/parser/parser_handle_pattern.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_statement.cpp b/toolchain/parser/parser_handle_statement.cpp index c9758e3918511..4063614f94010 100644 --- a/toolchain/parser/parser_handle_statement.cpp +++ b/toolchain/parser/parser_handle_statement.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { diff --git a/toolchain/parser/parser_handle_states.h b/toolchain/parser/parser_handle_states.h deleted file mode 100644 index da11a56fe5bd4..0000000000000 --- a/toolchain/parser/parser_handle_states.h +++ /dev/null @@ -1,20 +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 - -#ifndef CARBON_TOOLCHAIN_PARSER_PARSER_HANDLE_STATES_H_ -#define CARBON_TOOLCHAIN_PARSER_PARSER_HANDLE_STATES_H_ - -#include "toolchain/parser/parser_context.h" - -namespace Carbon { - -// `clang-format` has a bug with spacing around `->` returns in macros. See -// https://bugs.llvm.org/show_bug.cgi?id=48320 for details. -#define CARBON_PARSER_STATE(Name) \ - auto ParserHandle##Name(ParserContext& context)->void; -#include "toolchain/parser/parser_state.def" - -} // namespace Carbon - -#endif // CARBON_TOOLCHAIN_PARSER_PARSER_HANDLE_STATES_H_ diff --git a/toolchain/parser/parser_handle_type.cpp b/toolchain/parser/parser_handle_type.cpp index a1cedc0239fb8..8a9f3ccb2fc7b 100644 --- a/toolchain/parser/parser_handle_type.cpp +++ b/toolchain/parser/parser_handle_type.cpp @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/parser/parser_context.h" -#include "toolchain/parser/parser_handle_states.h" namespace Carbon { From 735b3618f67f57024a4ace44480bdc0ec7d717a3 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 18:39:59 +0000 Subject: [PATCH 05/29] x --- toolchain/parser/BUILD | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/toolchain/parser/BUILD b/toolchain/parser/BUILD index 4b20716ca03f7..b71c1ea6e1ae7 100644 --- a/toolchain/parser/BUILD +++ b/toolchain/parser/BUILD @@ -31,23 +31,11 @@ cc_library( "parse_tree.cpp", "parser_context.cpp", "parser_context.h", - "parser_handle_brace_expression.cpp", - "parser_handle_call_expression.cpp", - "parser_handle_code_block.cpp", - "parser_handle_declaration_name_and_params.cpp", - "parser_handle_declaration_scope_loop.cpp", - "parser_handle_designator.cpp", - "parser_handle_expression.cpp", - "parser_handle_function.cpp", - "parser_handle_package.cpp", - "parser_handle_parameter.cpp", - "parser_handle_paren_condition.cpp", - "parser_handle_paren_expression.cpp", - "parser_handle_pattern.cpp", - "parser_handle_statement.cpp", - "parser_handle_type.cpp", - "parser_handle_var.cpp", - ], + ] + + # Glob handler files to avoid missing anyway. + glob([ + "parser_handle_*.cpp", + ]), hdrs = ["parse_tree.h"], deps = [ ":parse_node_kind", From 41b90b53e2c027701715118c13fd9800ed06f34c Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 21:56:42 +0000 Subject: [PATCH 06/29] drafting --- toolchain/common/BUILD | 10 +- .../common/pretty_stack_trace_function.h | 28 + toolchain/semantics/BUILD | 11 +- toolchain/semantics/semantics_context.cpp | 283 ++++ ...rse_tree_handler.h => semantics_context.h} | 271 ++-- toolchain/semantics/semantics_handle_x.cpp | 847 +++++++++++ toolchain/semantics/semantics_ir.cpp | 36 +- toolchain/semantics/semantics_ir.h | 114 +- .../semantics_parse_tree_handler.cpp | 1249 ----------------- 9 files changed, 1442 insertions(+), 1407 deletions(-) create mode 100644 toolchain/common/pretty_stack_trace_function.h create mode 100644 toolchain/semantics/semantics_context.cpp rename toolchain/semantics/{semantics_parse_tree_handler.h => semantics_context.h} (66%) create mode 100644 toolchain/semantics/semantics_handle_x.cpp delete mode 100644 toolchain/semantics/semantics_parse_tree_handler.cpp diff --git a/toolchain/common/BUILD b/toolchain/common/BUILD index 55aed41553ba4..ddb7036cd2086 100644 --- a/toolchain/common/BUILD +++ b/toolchain/common/BUILD @@ -2,7 +2,7 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -package(default_visibility = ["//visibility:public"]) +package(default_visibility = ["//toolchain:__subpackages__"]) cc_library( name = "index_base", @@ -13,6 +13,14 @@ cc_library( ], ) +cc_library( + name = "pretty_stack_trace_function", + hdrs = ["pretty_stack_trace_function.h"], + deps = [ + "@llvm-project//llvm:Support", + ], +) + cc_library( name = "yaml_test_helpers", testonly = 1, diff --git a/toolchain/common/pretty_stack_trace_function.h b/toolchain/common/pretty_stack_trace_function.h new file mode 100644 index 0000000000000..a6b7e9a297451 --- /dev/null +++ b/toolchain/common/pretty_stack_trace_function.h @@ -0,0 +1,28 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_COMMON_PRETTY_STACK_TRACE_FUNCTION_H_ +#define CARBON_TOOLCHAIN_COMMON_PRETTY_STACK_TRACE_FUNCTION_H_ + +#include + +#include "llvm/Support/PrettyStackTrace.h" + +namespace Carbon { + +class PrettyStackTraceFunction : public llvm::PrettyStackTraceEntry { + public: + explicit PrettyStackTraceFunction(std::function fn) + : fn_(std::move(fn)) {} + ~PrettyStackTraceFunction() override = default; + + auto print(llvm::raw_ostream& output) const -> void override { fn_(output); } + + private: + const std::function fn_; +}; + +} // namespace Carbon + +#endif // CARBON_TOOLCHAIN_COMMON_PRETTY_STACK_TRACE_FUNCTION_H_ diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index 9e8761eadf342..1d2caba58e592 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -66,11 +66,15 @@ cc_library( name = "semantics_ir", srcs = [ "semantics_ir.cpp", - "semantics_parse_tree_handler.cpp", - ], + "semantics_context.cpp", + ] + + # Glob handler files to avoid missing anyway. + glob([ + "semantics_handle_*.cpp", + ]), hdrs = [ + "semantics_context.h", "semantics_ir.h", - "semantics_parse_tree_handler.h", ], deps = [ ":semantics_builtin_kind", @@ -80,6 +84,7 @@ cc_library( "//common:check", "//common:ostream", "//common:vlog", + "//toolchain/common:pretty_stack_trace_function", "//toolchain/diagnostics:diagnostic_kind", "//toolchain/lexer:numeric_literal", "//toolchain/lexer:token_kind", diff --git a/toolchain/semantics/semantics_context.cpp b/toolchain/semantics/semantics_context.cpp new file mode 100644 index 0000000000000..83f0438b1eb42 --- /dev/null +++ b/toolchain/semantics/semantics_context.cpp @@ -0,0 +1,283 @@ +// 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 "toolchain/semantics/semantics_context.h" + +#include + +#include "common/vlog.h" +#include "toolchain/diagnostics/diagnostic_kind.h" +#include "toolchain/lexer/token_kind.h" +#include "toolchain/lexer/tokenized_buffer.h" +#include "toolchain/parser/parse_node_kind.h" +#include "toolchain/semantics/semantics_ir.h" +#include "toolchain/semantics/semantics_node.h" +#include "toolchain/semantics/semantics_node_block_stack.h" + +namespace Carbon { + +auto SemanticsContext::AddNode(SemanticsNode node) -> SemanticsNodeId { + auto block = node_block_stack_.PeekForAdd(); + CARBON_VLOG() << "AddNode " << block << ": " << node << "\n"; + return semantics_->AddNode(block, node); +} + +auto SemanticsContext::AddNodeAndPush(ParseTree::Node parse_node, + SemanticsNode node) -> void { + auto node_id = AddNode(node); + node_stack_.Push(parse_node, node_id); +} + +auto SemanticsContext::AddNameToLookup(ParseTree::Node name_node, + SemanticsStringId name_id, + SemanticsNodeId target_id) -> void { + auto [it, inserted] = current_scope().names.insert(name_id); + if (inserted) { + name_lookup_[name_id].push_back(target_id); + } else { + CARBON_DIAGNOSTIC(NameRedefined, Error, "Redefining {0} in the same scope.", + llvm::StringRef); + CARBON_DIAGNOSTIC(PreviousDefinition, Note, "Previous definition is here."); + auto prev_def_id = name_lookup_[name_id].back(); + auto prev_def = semantics_->GetNode(prev_def_id); + + emitter_->Build(name_node, NameRedefined, semantics_->GetString(name_id)) + .Note(prev_def.parse_node(), PreviousDefinition) + .Emit(); + } +} + +auto SemanticsContext::BindName(ParseTree::Node name_node, + SemanticsNodeId type_id, + SemanticsNodeId target_id) + -> SemanticsStringId { + CARBON_CHECK(parse_tree_->node_kind(name_node) == ParseNodeKind::DeclaredName) + << parse_tree_->node_kind(name_node); + auto name_str = parse_tree_->GetNodeText(name_node); + auto name_id = semantics_->AddString(name_str); + + AddNode( + SemanticsNode::BindName::Make(name_node, type_id, name_id, target_id)); + AddNameToLookup(name_node, name_id, target_id); + return name_id; +} + +auto SemanticsContext::PushScope() -> void { scope_stack_.push_back({}); } + +auto SemanticsContext::PopScope() -> void { + auto scope = scope_stack_.pop_back_val(); + for (const auto& str_id : scope.names) { + auto it = name_lookup_.find(str_id); + if (it->second.size() == 1) { + // Erase names that no longer resolve. + name_lookup_.erase(it); + } else { + it->second.pop_back(); + } + } +} + +auto SemanticsContext::ImplicitAsForArgs( + SemanticsNodeBlockId /*arg_ir_id*/, SemanticsNodeBlockId arg_refs_id, + ParseTree::Node param_parse_node, SemanticsNodeBlockId param_refs_id, + DiagnosticEmitter::DiagnosticBuilder* diagnostic) -> bool { + // If both arguments and parameters are empty, return quickly. Otherwise, + // we'll fetch both so that errors are consistent. + if (arg_refs_id == SemanticsNodeBlockId::Empty && + param_refs_id == SemanticsNodeBlockId::Empty) { + return true; + } + + auto arg_refs = semantics_->GetNodeBlock(arg_refs_id); + auto param_refs = semantics_->GetNodeBlock(param_refs_id); + + // If sizes mismatch, fail early. + if (arg_refs.size() != param_refs.size()) { + CARBON_CHECK(diagnostic != nullptr) << "Should have validated first"; + CARBON_DIAGNOSTIC(CallArgCountMismatch, Note, + "Callable cannot be used: Received {0} argument(s), but " + "require {1} argument(s).", + int, int); + diagnostic->Note(param_parse_node, CallArgCountMismatch, arg_refs.size(), + param_refs.size()); + return false; + } + + // Check type conversions per-element. + // TODO: arg_ir_id is passed so that implicit conversions can be inserted. + // It's currently not supported, but will be needed. + for (size_t i = 0; i < arg_refs.size(); ++i) { + auto value_id = arg_refs[i]; + auto as_type_id = semantics_->GetNode(param_refs[i]).type_id(); + if (ImplicitAsImpl(value_id, as_type_id, + diagnostic == nullptr ? &value_id : nullptr) == + ImplicitAsKind::Incompatible) { + CARBON_CHECK(diagnostic != nullptr) << "Should have validated first"; + CARBON_DIAGNOSTIC(CallArgTypeMismatch, Note, + "Callable cannot be used: Cannot implicityly convert " + "argument {0} from `{1}` to `{2}`.", + size_t, std::string, std::string); + diagnostic->Note( + param_parse_node, CallArgTypeMismatch, i, + semantics_->StringifyNode(semantics_->GetNode(value_id).type_id()), + semantics_->StringifyNode(as_type_id)); + return false; + } + } + + return true; +} + +auto SemanticsContext::ImplicitAsRequired(ParseTree::Node parse_node, + SemanticsNodeId value_id, + SemanticsNodeId as_type_id) + -> SemanticsNodeId { + SemanticsNodeId output_value_id = value_id; + if (ImplicitAsImpl(value_id, as_type_id, &output_value_id) == + ImplicitAsKind::Incompatible) { + // Only error when the system is trying to use the result. + CARBON_DIAGNOSTIC(ImplicitAsConversionFailure, Error, + "Cannot implicitly convert from `{0}` to `{1}`.", + std::string, std::string); + emitter_ + ->Build( + parse_node, ImplicitAsConversionFailure, + semantics_->StringifyNode(semantics_->GetNode(value_id).type_id()), + semantics_->StringifyNode(as_type_id)) + .Emit(); + } + return output_value_id; +} + +auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id, + SemanticsNodeId as_type_id, + SemanticsNodeId* output_value_id) + -> ImplicitAsKind { + // Start by making sure both sides are valid. If any part is invalid, the + // result is invalid and we shouldn't error. + if (value_id == SemanticsNodeId::BuiltinInvalidType) { + // If the value is invalid, we can't do much, but do "succeed". + return ImplicitAsKind::Identical; + } + auto value_type_id = semantics_->GetNode(value_id).type_id(); + if (value_type_id == SemanticsNodeId::BuiltinInvalidType) { + return ImplicitAsKind::Identical; + } + if (as_type_id == SemanticsNodeId::BuiltinInvalidType) { + // Although the target type is invalid, this still changes the value. + if (output_value_id != nullptr) { + *output_value_id = SemanticsNodeId::BuiltinInvalidType; + } + return ImplicitAsKind::Compatible; + } + + if (value_type_id == as_type_id) { + // Type doesn't need to change. + return ImplicitAsKind::Identical; + } + + // When converting to a Type, there are some automatic conversions that can be + // done. + if (as_type_id == SemanticsNodeId::BuiltinTypeType) { + if (value_id == SemanticsNodeId::BuiltinEmptyTuple) { + if (output_value_id != nullptr) { + *output_value_id = SemanticsNodeId::BuiltinEmptyTupleType; + } + return ImplicitAsKind::Compatible; + } + if (value_id == SemanticsNodeId::BuiltinEmptyStruct) { + if (output_value_id != nullptr) { + *output_value_id = SemanticsNodeId::BuiltinEmptyStructType; + } + return ImplicitAsKind::Compatible; + } + } + + auto value_type = semantics_->GetNode(value_type_id); + auto as_type = semantics_->GetNode(as_type_id); + if (CanImplicitAsStruct(value_type, as_type)) { + // Under the current implementation, struct types are only allowed to + // ImplicitAs when they're equivalent. What's really missing is type + // consolidation such that this would fall under the above `value_type_id == + // as_type_id` case. In the future, this will need to handle actual + // conversions. + return ImplicitAsKind::Identical; + } + + if (output_value_id != nullptr) { + *output_value_id = SemanticsNodeId::BuiltinInvalidType; + } + return ImplicitAsKind::Incompatible; +} + +auto SemanticsContext::CanImplicitAsStruct(SemanticsNode value_type, + SemanticsNode as_type) -> bool { + if (value_type.kind() != SemanticsNodeKind::StructType || + as_type.kind() != SemanticsNodeKind::StructType) { + return false; + } + auto value_type_refs = + semantics_->GetNodeBlock(value_type.GetAsStructType().second); + auto as_type_refs = + semantics_->GetNodeBlock(as_type.GetAsStructType().second); + if (value_type_refs.size() != as_type_refs.size()) { + return false; + } + + for (int i = 0; i < static_cast(value_type_refs.size()); ++i) { + auto value_type_field = semantics_->GetNode(value_type_refs[i]); + auto as_type_field = semantics_->GetNode(as_type_refs[i]); + if (value_type_field.type_id() != as_type_field.type_id() || + value_type_field.GetAsStructTypeField() != + as_type_field.GetAsStructTypeField()) { + return false; + } + } + return true; +} + +auto SemanticsContext::ParamOrArgStart() -> void { + params_or_args_stack_.Push(); + node_block_stack_.Push(); +} + +auto SemanticsContext::ParamOrArgComma(bool for_args) -> void { + ParamOrArgSave(for_args); +} + +auto SemanticsContext::ParamOrArgEnd(bool for_args, ParseNodeKind start_kind) + -> std::pair { + if (parse_tree_->node_kind(node_stack_.PeekParseNode()) != start_kind) { + ParamOrArgSave(for_args); + } + return {node_block_stack_.Pop(), params_or_args_stack_.Pop()}; +} + +auto SemanticsContext::ParamOrArgSave(bool for_args) -> void { + SemanticsNodeId param_or_arg_id = SemanticsNodeId::Invalid; + if (for_args) { + // For an argument, we add a stub reference to the expression on the top of + // the stack. There may not be anything on the IR prior to this. + auto [entry_parse_node, entry_node_id] = + node_stack_.PopForParseNodeAndNodeId(); + param_or_arg_id = AddNode(SemanticsNode::StubReference::Make( + entry_parse_node, semantics_->GetNode(entry_node_id).type_id(), + entry_node_id)); + } else { + // For a parameter, there should always be something in the IR. + node_stack_.PopAndIgnore(); + auto ir_id = node_block_stack_.Peek(); + CARBON_CHECK(ir_id.is_valid()); + auto& ir = semantics_->GetNodeBlock(ir_id); + CARBON_CHECK(!ir.empty()) << "Should have had a param"; + param_or_arg_id = ir.back(); + } + + // Save the param or arg ID. + auto& params_or_args = + semantics_->GetNodeBlock(params_or_args_stack_.PeekForAdd()); + params_or_args.push_back(param_or_arg_id); +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_parse_tree_handler.h b/toolchain/semantics/semantics_context.h similarity index 66% rename from toolchain/semantics/semantics_parse_tree_handler.h rename to toolchain/semantics/semantics_context.h index 15f5e070f686d..d755c7f7a9a86 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.h +++ b/toolchain/semantics/semantics_context.h @@ -2,8 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ -#define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ +#ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_CONTEXT_H_ +#define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_CONTEXT_H_ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -17,35 +17,191 @@ namespace Carbon { // Handles processing of a ParseTree for semantics. -class SemanticsParseTreeHandler { +class SemanticsContext { public: // Stores references for work. - explicit SemanticsParseTreeHandler( - const TokenizedBuffer& tokens, - DiagnosticEmitter& emitter, const ParseTree& parse_tree, - SemanticsIR& semantics, llvm::raw_ostream* vlog_stream) + explicit SemanticsContext(const TokenizedBuffer& tokens, + DiagnosticEmitter& emitter, + const ParseTree& parse_tree, SemanticsIR& semantics, + llvm::raw_ostream* vlog_stream) : tokens_(&tokens), emitter_(&emitter), parse_tree_(&parse_tree), semantics_(&semantics), vlog_stream_(vlog_stream), node_stack_(parse_tree, vlog_stream), - node_block_stack_("node_block_stack_", semantics.node_blocks_, + node_block_stack_("node_block_stack_", semantics.node_blocks(), vlog_stream), - params_or_args_stack_("params_or_args_stack_", semantics.node_blocks_, + params_or_args_stack_("params_or_args_stack_", semantics.node_blocks(), vlog_stream), - args_type_info_stack_("args_type_info_stack_", semantics.node_blocks_, + args_type_info_stack_("args_type_info_stack_", semantics.node_blocks(), vlog_stream) {} - // Outputs the ParseTree information into SemanticsIR. - auto Build() -> void; + // Marks an implementation TODO. Always returns false. + auto TODO(ParseTree::Node parse_node, std::string label) -> bool { + CARBON_DIAGNOSTIC(SemanticsTodo, Error, "Semantics TODO: {0}", std::string); + emitter_->Emit(parse_node, SemanticsTodo, std::move(label)); + return false; + } - private: - // Prints the node_stack_ on stack dumps. - class PrettyStackTraceNodeStack; - // Prints the node_block_stack_ on stack dumps. - class PrettyStackTraceNodeBlockStack; + // Runs verification that the processing cleanly finished. + auto VerifyOnFinish() -> void { + // Information in all the various context objects should be cleaned up as + // various pieces of context go out of scope. At this point, nothing should + // remain. + // node_stack_ will still contain top-level entities. + CARBON_CHECK(name_lookup_.empty()) << name_lookup_.size(); + CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size(); + CARBON_CHECK(node_block_stack_.empty()) << node_block_stack_.size(); + CARBON_CHECK(params_or_args_stack_.empty()) << params_or_args_stack_.size(); + } + + // Pushes a new scope onto scope_stack_. + auto PushScope() -> void; + + // Pops the top scope from scope_stack_, cleaning up names from name_lookup_. + auto PopScope() -> void; + + // Adds a node to the current block, returning the produced ID. + auto AddNode(SemanticsNode node) -> SemanticsNodeId; + + // Pushes a parse tree node onto the stack, storing the SemanticsNode as the + // result. + auto AddNodeAndPush(ParseTree::Node parse_node, SemanticsNode node) -> void; + + // Runs ImplicitAsImpl for a set of arguments and parameters. + // + // This will eventually need to support checking against multiple possible + // overloads, multiple of which may be possible but not "best". While this can + // currently be done by calling twice, toggling `apply_implicit_as`, in the + // future we may want to remember the right implicit conversions to do for + // valid cases in order to efficiently handle generics. + auto ImplicitAsForArgs( + SemanticsNodeBlockId arg_ir_id, SemanticsNodeBlockId arg_refs_id, + ParseTree::Node param_parse_node, SemanticsNodeBlockId param_refs_id, + DiagnosticEmitter::DiagnosticBuilder* diagnostic) + -> bool; + + // Runs ImplicitAsImpl for a situation where a cast is required, returning the + // updated `value_id`. Prints a diagnostic and returns an InvalidType if + // unsupported. + auto ImplicitAsRequired(ParseTree::Node parse_node, SemanticsNodeId value_id, + SemanticsNodeId as_type_id) -> SemanticsNodeId; + + // Starts handling parameters or arguments. + auto ParamOrArgStart() -> void; + + // On a comma, pushes the entry. On return, the top of node_stack_ will be + // start_kind. + auto ParamOrArgComma(bool for_args) -> void; + + // Detects whether there's an entry to push. On return, the top of + // node_stack_ will be start_kind, and the caller should do type-specific + // processing. Returns a pair of {ir_id, refs_id}. + auto ParamOrArgEnd(bool for_args, ParseNodeKind start_kind) + -> std::pair; + + // Saves a parameter from the top block in node_stack_ to the top block in + // params_or_args_stack_. If for_args, adds a StubReference of the previous + // node's result to the IR. + // + // This should only be called by other ParamOrArg functions, not directly. + auto ParamOrArgSave(bool for_args) -> void; + + // Prints information for a stack dump. + auto PrintForStackDump(llvm::raw_ostream& output) const -> void { + node_stack_.PrintForStackDump(output); + node_block_stack_.PrintForStackDump(output); + params_or_args_stack_.PrintForStackDump(output); + args_type_info_stack_.PrintForStackDump(output); + } + + // Adds a name to name lookup. + auto AddNameToLookup(ParseTree::Node name_node, SemanticsStringId name_id, + SemanticsNodeId target_id) -> void; + + // Temporarily remove name lookup entries added by the `var`. These will be + // restored by `VariableDeclaration` using `ReaddNameToLookup`. + auto TempRemoveLatestNameFromLookup() -> SemanticsNodeId { + // Save the storage ID. + auto it = name_lookup_.find( + node_stack_.PeekForNameId(ParseNodeKind::PatternBinding)); + CARBON_CHECK(it != name_lookup_.end()); + CARBON_CHECK(!it->second.empty()); + auto storage_id = it->second.back(); + + // Pop the name from lookup. + if (it->second.size() == 1) { + // Erase names that no longer resolve. + name_lookup_.erase(it); + } else { + it->second.pop_back(); + } + return storage_id; + } + + // Re-adds a name to name lookup. This is typically done through BindName, but + // can also be used to restore removed names. + auto ReaddNameToLookup(SemanticsStringId name_id, SemanticsNodeId storage_id) + -> void { + name_lookup_[name_id].push_back(storage_id); + } + + // Lookup up a name, returning the referenced node. + auto Lookup(ParseTree::Node parse_node, llvm::StringRef name) + -> SemanticsNodeId { + CARBON_DIAGNOSTIC(NameNotFound, Error, "Name {0} not found", + llvm::StringRef); + + auto name_id = semantics_->GetStringID(name); + if (!name_id) { + emitter_->Emit(parse_node, NameNotFound, name); + return SemanticsNodeId::BuiltinInvalidType; + } + + auto it = name_lookup_.find(*name_id); + if (it == name_lookup_.end()) { + emitter_->Emit(parse_node, NameNotFound, name); + return SemanticsNodeId::BuiltinInvalidType; + } + CARBON_CHECK(!it->second.empty()) << "Should have been erased: " << name; + + // TODO: Check for ambiguous lookups. + return it->second.back(); + } + + // Binds a DeclaredName to a target node with the given type. + auto BindName(ParseTree::Node name_node, SemanticsNodeId type_id, + SemanticsNodeId target_id) -> SemanticsStringId; + + auto tokens() -> const TokenizedBuffer& { return *tokens_; } + + auto emitter() -> DiagnosticEmitter& { return *emitter_; } + auto parse_tree() -> const ParseTree& { return *parse_tree_; } + + auto semantics() -> SemanticsIR& { return *semantics_; } + + auto node_stack() -> SemanticsNodeStack& { return node_stack_; } + + auto node_block_stack() -> SemanticsNodeBlockStack& { + return node_block_stack_; + } + + auto args_type_info_stack() -> SemanticsNodeBlockStack& { + return args_type_info_stack_; + } + + auto finished_params_stack() -> llvm::SmallVector< + std::pair> { + return finished_params_stack_; + } + + auto return_scope_stack() -> llvm::SmallVector& { + return return_scope_stack_; + } + + private: // For CanImplicitAs, the detected conversion to apply. enum ImplicitAsKind { // Incompatible types. @@ -84,53 +240,6 @@ class SemanticsParseTreeHandler { // TODO: This likely needs to track things which need to be destructed. }; - // Adds a node to the current block, returning the produced ID. - auto AddNode(SemanticsNode node) -> SemanticsNodeId; - - // Pushes a parse tree node onto the stack, storing the SemanticsNode as the - // result. - auto AddNodeAndPush(ParseTree::Node parse_node, SemanticsNode node) -> void; - - // Adds a name to name lookup. - auto AddNameToLookup(ParseTree::Node name_node, SemanticsStringId name_id, - SemanticsNodeId target_id) -> void; - - // Re-adds a name to name lookup. This is typically done through BindName, but - // can also be used to restore removed names. - auto ReaddNameToLookup(SemanticsStringId name_id, SemanticsNodeId storage_id) - -> void { - name_lookup_[name_id].push_back(storage_id); - } - - // Binds a DeclaredName to a target node with the given type. - auto BindName(ParseTree::Node name_node, SemanticsNodeId type_id, - SemanticsNodeId target_id) -> SemanticsStringId; - - // Pushes a new scope onto scope_stack_. - auto PushScope() -> void; - - // Pops the top scope from scope_stack_, cleaning up names from name_lookup_. - auto PopScope() -> void; - - // Runs ImplicitAsImpl for a set of arguments and parameters. - // - // This will eventually need to support checking against multiple possible - // overloads, multiple of which may be possible but not "best". While this can - // currently be done by calling twice, toggling `apply_implicit_as`, in the - // future we may want to remember the right implicit conversions to do for - // valid cases in order to efficiently handle generics. - auto ImplicitAsForArgs( - SemanticsNodeBlockId arg_ir_id, SemanticsNodeBlockId arg_refs_id, - ParseTree::Node param_parse_node, SemanticsNodeBlockId param_refs_id, - DiagnosticEmitter::DiagnosticBuilder* diagnostic) - -> bool; - - // Runs ImplicitAsImpl for a situation where a cast is required, returning the - // updated `value_id`. Prints a diagnostic and returns an InvalidType if - // unsupported. - auto ImplicitAsRequired(ParseTree::Node parse_node, SemanticsNodeId value_id, - SemanticsNodeId as_type_id) -> SemanticsNodeId; - // Runs ImplicitAs behavior to convert `value` to `as_type`, returning the // result type. The result will be the node to use to replace `value`. // @@ -147,31 +256,6 @@ class SemanticsParseTreeHandler { auto CanImplicitAsStruct(SemanticsNode value_type, SemanticsNode as_type) -> bool; - // Starts handling parameters or arguments. - auto ParamOrArgStart() -> void; - - // On a comma, pushes the entry. On return, the top of node_stack_ will be - // start_kind. - auto ParamOrArgComma(bool for_args) -> void; - - // Detects whether there's an entry to push. On return, the top of - // node_stack_ will be start_kind, and the caller should do type-specific - // processing. Returns a pair of {ir_id, refs_id}. - auto ParamOrArgEnd(bool for_args, ParseNodeKind start_kind) - -> std::pair; - - // Saves a parameter from the top block in node_stack_ to the top block in - // params_or_args_stack_. If for_args, adds a StubReference of the previous - // node's result to the IR. - // - // This should only be called by other ParamOrArg functions, not directly. - auto ParamOrArgSave(bool for_args) -> void; - - // Parse node handlers. Returns false for unrecoverable errors. -#define CARBON_PARSE_NODE_KIND(Name) \ - auto Handle##Name(ParseTree::Node parse_node)->bool; -#include "toolchain/parser/parse_node_kind.def" - auto current_scope() -> ScopeStackEntry& { return scope_stack_.back(); } // Tokens for getting data on literals. @@ -231,6 +315,13 @@ class SemanticsParseTreeHandler { name_lookup_; }; +// Parse node handlers. Returns false for unrecoverable errors. +#define CARBON_PARSE_NODE_KIND(Name) \ + auto SemanticsHandle##Name(SemanticsContext& context, \ + ParseTree::Node parse_node) \ + ->bool; +#include "toolchain/parser/parse_node_kind.def" + } // namespace Carbon -#endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ +#endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_CONTEXT_H_ diff --git a/toolchain/semantics/semantics_handle_x.cpp b/toolchain/semantics/semantics_handle_x.cpp new file mode 100644 index 0000000000000..68eadf4118c57 --- /dev/null +++ b/toolchain/semantics/semantics_handle_x.cpp @@ -0,0 +1,847 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandleAddress(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleAddress"); +} + +auto SemanticsHandleBreakStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleBreakStatement"); +} + +auto SemanticsHandleBreakStatementStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleBreakStatementStart"); +} + +auto SemanticsHandleCallExpression(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/true, ParseNodeKind::CallExpressionStart); + + // TODO: Convert to call expression. + auto [call_expr_parse_node, name_id] = + context.node_stack().PopForParseNodeAndNodeId( + ParseNodeKind::CallExpressionStart); + auto name_node = context.semantics().GetNode(name_id); + if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) { + // TODO: Work on error. + context.TODO(parse_node, "Not a callable name"); + context.node_stack().Push(parse_node, name_id); + return true; + } + + auto [_, callable_id] = name_node.GetAsFunctionDeclaration(); + auto callable = context.semantics().GetCallable(callable_id); + + CARBON_DIAGNOSTIC(NoMatchingCall, Error, "No matching callable was found."); + auto diagnostic = + context.emitter().Build(call_expr_parse_node, NoMatchingCall); + if (!context.ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), + callable.param_refs_id, &diagnostic)) { + diagnostic.Emit(); + context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinInvalidType); + return true; + } + + CARBON_CHECK(context.ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), + callable.param_refs_id, + /*diagnostic=*/nullptr)); + + auto call_id = context.semantics().AddCall({ir_id, refs_id}); + // TODO: Propagate return types from callable. + auto call_node_id = context.AddNode(SemanticsNode::Call::Make( + call_expr_parse_node, callable.return_type_id, call_id, callable_id)); + + context.node_stack().Push(parse_node, call_node_id); + return true; +} + +auto SemanticsHandleCallExpressionComma(SemanticsContext& context, + ParseTree::Node /*parse_node*/) + -> bool { + context.ParamOrArgComma(/*for_args=*/true); + return true; +} + +auto SemanticsHandleCallExpressionStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto name_id = + context.node_stack().PopForNodeId(ParseNodeKind::NameReference); + context.node_stack().Push(parse_node, name_id); + context.ParamOrArgStart(); + return true; +} + +auto SemanticsHandleClassDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassDeclaration"); +} + +auto SemanticsHandleClassDefinition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassDefinition"); +} + +auto SemanticsHandleClassDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassDefinitionStart"); +} + +auto SemanticsHandleClassIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassIntroducer"); +} + +auto SemanticsHandleCodeBlock(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleCodeBlock"); +} + +auto SemanticsHandleCodeBlockStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleCodeBlockStart"); +} + +auto SemanticsHandleContinueStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleContinueStatement"); +} + +auto SemanticsHandleContinueStatementStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleContinueStatementStart"); +} + +auto SemanticsHandleDeclaredName(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // The parent is responsible for binding the name. + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleDeducedParameterList(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleDeducedParameterList"); +} + +auto SemanticsHandleDeducedParameterListStart(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleDeducedParameterListStart"); +} + +auto SemanticsHandleDesignatedName(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto name_str = context.parse_tree().GetNodeText(parse_node); + auto name_id = context.semantics().AddString(name_str); + // The parent is responsible for binding the name. + context.node_stack().Push(parse_node, name_id); + return true; +} + +auto SemanticsHandleDesignatorExpression(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [_, name_id] = context.node_stack().PopForParseNodeAndNameId( + ParseNodeKind::DesignatedName); + + auto base_id = context.node_stack().PopForNodeId(); + auto base = context.semantics().GetNode(base_id); + auto base_type = context.semantics().GetNode(base.type_id()); + + switch (base_type.kind()) { + case SemanticsNodeKind::StructType: { + auto refs = + context.semantics().GetNodeBlock(base_type.GetAsStructType().second); + // TODO: Do we need to optimize this with a lookup table for O(1)? + for (int i = 0; i < static_cast(refs.size()); ++i) { + auto ref = context.semantics().GetNode(refs[i]); + if (name_id == ref.GetAsStructTypeField()) { + context.AddNodeAndPush( + parse_node, + SemanticsNode::StructMemberAccess::Make( + parse_node, ref.type_id(), base_id, SemanticsMemberIndex(i))); + return true; + } + } + CARBON_DIAGNOSTIC(DesignatorExpressionNameNotFound, Error, + "Type `{0}` does not have a member `{1}`.", std::string, + llvm::StringRef); + context.emitter().Emit(parse_node, DesignatorExpressionNameNotFound, + context.semantics().StringifyNode(base.type_id()), + context.semantics().GetString(name_id)); + break; + } + default: { + CARBON_DIAGNOSTIC(DesignatorExpressionUnsupported, Error, + "Type `{0}` does not support designator expressions.", + std::string); + context.emitter().Emit(parse_node, DesignatorExpressionUnsupported, + context.semantics().StringifyNode(base.type_id())); + break; + } + } + + // Should only be reached on error. + context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinInvalidType); + return true; +} + +auto SemanticsHandleEmptyDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // Empty declarations have no actions associated, but we still balance the + // tree. + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleExpressionStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // Pop the expression without investigating its contents. + // TODO: This will probably eventually need to do some "do not discard" + // analysis. + context.node_stack().PopAndDiscardId(); + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleFileEnd(SemanticsContext& /*context*/, + ParseTree::Node /*parse_node*/) -> bool { + // Do nothing, no need to balance this node. + return true; +} + +auto SemanticsHandleForHeader(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleForHeader"); +} + +auto SemanticsHandleForHeaderStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleForHeaderStart"); +} + +auto SemanticsHandleForIn(SemanticsContext& context, ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleForIn"); +} + +auto SemanticsHandleForStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleForStatement"); +} + +auto SemanticsHandleFunctionDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleFunctionDeclaration"); +} + +auto SemanticsHandleFunctionDefinition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // Merges code block children up under the FunctionDefinitionStart. + while (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) != + ParseNodeKind::FunctionDefinitionStart) { + context.node_stack().PopAndIgnore(); + } + auto decl_id = + context.node_stack().PopForNodeId(ParseNodeKind::FunctionDefinitionStart); + + context.return_scope_stack().pop_back(); + context.PopScope(); + auto block_id = context.node_block_stack().Pop(); + context.AddNode( + SemanticsNode::FunctionDefinition::Make(parse_node, decl_id, block_id)); + context.node_stack().Push(parse_node); + + return true; +} + +auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + SemanticsNodeId return_type_id = SemanticsNodeId::Invalid; + if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == + ParseNodeKind::ReturnType) { + return_type_id = + context.node_stack().PopForNodeId(ParseNodeKind::ReturnType); + } + context.node_stack().PopForSoloParseNode(ParseNodeKind::ParameterList); + auto [param_ir_id, param_refs_id] = + context.finished_params_stack().pop_back_val(); + auto name_node = + context.node_stack().PopForSoloParseNode(ParseNodeKind::DeclaredName); + auto fn_node = context.node_stack().PopForSoloParseNode( + ParseNodeKind::FunctionIntroducer); + + auto name_str = context.parse_tree().GetNodeText(name_node); + auto name_id = context.semantics().AddString(name_str); + + auto callable_id = + context.semantics().AddCallable({.param_ir_id = param_ir_id, + .param_refs_id = param_refs_id, + .return_type_id = return_type_id}); + auto decl_id = context.AddNode( + SemanticsNode::FunctionDeclaration::Make(fn_node, name_id, callable_id)); + context.AddNameToLookup(name_node, name_id, decl_id); + + context.node_block_stack().Push(); + context.PushScope(); + context.return_scope_stack().push_back(decl_id); + context.node_stack().Push(parse_node, decl_id); + + return true; +} + +auto SemanticsHandleFunctionIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // No action, just a bracketing node. + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleGenericPatternBinding(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "GenericPatternBinding"); +} + +auto SemanticsHandleIfCondition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleIfCondition"); +} + +auto SemanticsHandleIfConditionStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleIfConditionStart"); +} + +auto SemanticsHandleIfStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleIfStatement"); +} + +auto SemanticsHandleIfStatementElse(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleIfStatementElse"); +} + +auto SemanticsHandleInfixOperator(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto rhs_id = context.node_stack().PopForNodeId(); + auto lhs_id = context.node_stack().PopForNodeId(); + + // TODO: This should search for a compatible interface. For now, it's a very + // trivial check of validity on the operation. + lhs_id = context.ImplicitAsRequired( + parse_node, lhs_id, context.semantics().GetNode(rhs_id).type_id()); + + // Figure out the operator for the token. + auto token = context.parse_tree().node_token(parse_node); + switch (auto token_kind = context.tokens().GetKind(token)) { + case TokenKind::Plus: + context.AddNodeAndPush( + parse_node, + SemanticsNode::BinaryOperatorAdd::Make( + parse_node, context.semantics().GetNode(lhs_id).type_id(), lhs_id, + rhs_id)); + break; + default: + return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind)); + } + + return true; +} + +auto SemanticsHandleInterfaceDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInterfaceDeclaration"); +} + +auto SemanticsHandleInterfaceDefinition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInterfaceDefinition"); +} + +auto SemanticsHandleInterfaceDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleInterfaceDefinitionStart"); +} + +auto SemanticsHandleInterfaceIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInterfaceIntroducer"); +} + +auto SemanticsHandleInvalidParse(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInvalidParse"); +} + +auto SemanticsHandleLiteral(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto token = context.parse_tree().node_token(parse_node); + switch (auto token_kind = context.tokens().GetKind(token)) { + case TokenKind::IntegerLiteral: { + auto id = context.semantics().AddIntegerLiteral( + context.tokens().GetIntegerLiteral(token)); + context.AddNodeAndPush( + parse_node, SemanticsNode::IntegerLiteral::Make(parse_node, id)); + break; + } + case TokenKind::RealLiteral: { + auto token_value = context.tokens().GetRealLiteral(token); + auto id = context.semantics().AddRealLiteral( + {.mantissa = token_value.Mantissa(), + .exponent = token_value.Exponent(), + .is_decimal = token_value.IsDecimal()}); + context.AddNodeAndPush(parse_node, + SemanticsNode::RealLiteral::Make(parse_node, id)); + break; + } + case TokenKind::StringLiteral: { + auto id = context.semantics().AddString( + context.tokens().GetStringLiteral(token)); + context.AddNodeAndPush( + parse_node, SemanticsNode::StringLiteral::Make(parse_node, id)); + break; + } + case TokenKind::IntegerTypeLiteral: { + auto text = context.tokens().GetTokenText(token); + if (text != "i32") { + return context.TODO(parse_node, "Currently only i32 is allowed"); + } + context.node_stack().Push(parse_node, + SemanticsNodeId::BuiltinIntegerType); + break; + } + case TokenKind::FloatingPointTypeLiteral: { + auto text = context.tokens().GetTokenText(token); + if (text != "f64") { + return context.TODO(parse_node, "Currently only f64 is allowed"); + } + context.node_stack().Push(parse_node, + SemanticsNodeId::BuiltinFloatingPointType); + break; + } + case TokenKind::StringTypeLiteral: { + context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinStringType); + break; + } + default: { + return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind)); + } + } + + return true; +} + +auto SemanticsHandleNameReference(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto name = context.parse_tree().GetNodeText(parse_node); + context.node_stack().Push(parse_node, context.Lookup(parse_node, name)); + return true; +} + +auto SemanticsHandleNamedConstraintDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleNamedConstraintDeclaration"); +} + +auto SemanticsHandleNamedConstraintDefinition(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleNamedConstraintDefinition"); +} + +auto SemanticsHandleNamedConstraintDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleNamedConstraintDefinitionStart"); +} + +auto SemanticsHandleNamedConstraintIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleNamedConstraintIntroducer"); +} + +auto SemanticsHandlePackageApi(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageApi"); +} + +auto SemanticsHandlePackageDirective(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageDirective"); +} + +auto SemanticsHandlePackageImpl(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageImpl"); +} + +auto SemanticsHandlePackageIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageIntroducer"); +} + +auto SemanticsHandlePackageLibrary(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageLibrary"); +} + +auto SemanticsHandleParameterList(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/false, ParseNodeKind::ParameterListStart); + + context.PopScope(); + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::ParameterListStart); + context.finished_params_stack().push_back({ir_id, refs_id}); + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleParameterListComma(SemanticsContext& context, + ParseTree::Node /*parse_node*/) -> bool { + context.ParamOrArgComma(/*for_args=*/false); + return true; +} + +auto SemanticsHandleParameterListStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + context.PushScope(); + context.node_stack().Push(parse_node); + context.ParamOrArgStart(); + return true; +} + +auto SemanticsHandleParenExpression(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleParenExpression"); +} + +auto SemanticsHandleParenExpressionOrTupleLiteralStart( + SemanticsContext& context, ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleParenExpressionOrTupleLiteralStart"); +} + +auto SemanticsHandlePatternBinding(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [type_node, parsed_type_id] = + context.node_stack().PopForParseNodeAndNodeId(); + SemanticsNodeId cast_type_id = context.ImplicitAsRequired( + type_node, parsed_type_id, SemanticsNodeId::BuiltinTypeType); + + // Get the name. + auto name_node = context.node_stack().PopForSoloParseNode(); + + // Allocate storage, linked to the name for error locations. + auto storage_id = + context.AddNode(SemanticsNode::VarStorage::Make(name_node, cast_type_id)); + + // Bind the name to storage. + auto name_id = context.BindName(name_node, cast_type_id, storage_id); + + // If this node's result is used, it'll be for either the name or the + // storage address. The storage address can be found through the name, so we + // push the name. + context.node_stack().Push(parse_node, name_id); + + return true; +} + +auto SemanticsHandlePostfixOperator(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePostfixOperator"); +} + +auto SemanticsHandlePrefixOperator(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePrefixOperator"); +} + +auto SemanticsHandleReturnStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + CARBON_CHECK(!context.return_scope_stack().empty()); + const auto& fn_node = + context.semantics().GetNode(context.return_scope_stack().back()); + const auto callable = context.semantics().GetCallable( + fn_node.GetAsFunctionDeclaration().second); + + if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == + ParseNodeKind::ReturnStatementStart) { + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::ReturnStatementStart); + + if (callable.return_type_id.is_valid()) { + // TODO: Add a note pointing at the return type's parse node. + CARBON_DIAGNOSTIC(ReturnStatementMissingExpression, Error, + "Must return a {0}.", std::string); + context.emitter() + .Build(parse_node, ReturnStatementMissingExpression, + context.semantics().StringifyNode(callable.return_type_id)) + .Emit(); + } + + context.AddNodeAndPush(parse_node, SemanticsNode::Return::Make(parse_node)); + } else { + auto arg = context.node_stack().PopForNodeId(); + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::ReturnStatementStart); + + if (!callable.return_type_id.is_valid()) { + CARBON_DIAGNOSTIC( + ReturnStatementDisallowExpression, Error, + "No return expression should be provided in this context."); + CARBON_DIAGNOSTIC(ReturnStatementImplicitNote, Note, + "There was no return type provided."); + context.emitter() + .Build(parse_node, ReturnStatementDisallowExpression) + .Note(fn_node.parse_node(), ReturnStatementImplicitNote) + .Emit(); + } else { + arg = + context.ImplicitAsRequired(parse_node, arg, callable.return_type_id); + } + + context.AddNodeAndPush( + parse_node, + SemanticsNode::ReturnExpression::Make( + parse_node, context.semantics().GetNode(arg).type_id(), arg)); + } + return true; +} + +auto SemanticsHandleReturnStatementStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // No action, just a bracketing node. + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleReturnType(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // Propagate the type expression. + auto [type_parse_node, type_node_id] = + context.node_stack().PopForParseNodeAndNodeId(); + auto cast_node_id = context.ImplicitAsRequired( + type_parse_node, type_node_id, SemanticsNodeId::BuiltinTypeType); + context.node_stack().Push(parse_node, cast_node_id); + return true; +} + +auto SemanticsHandleSelfTypeIdentifier(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleSelfTypeIdentifier"); +} + +auto SemanticsHandleSelfValueIdentifier(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleSelfValueIdentifier"); +} + +auto SemanticsHandleStructComma(SemanticsContext& context, + ParseTree::Node /*parse_node*/) -> bool { + context.ParamOrArgComma( + /*for_args=*/context.parse_tree().node_kind( + context.node_stack().PeekParseNode()) != + ParseNodeKind::StructFieldType); + return true; +} + +auto SemanticsHandleStructFieldDesignator(SemanticsContext& context, + ParseTree::Node /*parse_node*/) + -> bool { + // This leaves the designated name on top because the `.` isn't interesting. + CARBON_CHECK( + context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == + ParseNodeKind::DesignatedName); + return true; +} + +auto SemanticsHandleStructFieldType(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [type_node, type_id] = context.node_stack().PopForParseNodeAndNodeId(); + SemanticsNodeId cast_type_id = context.ImplicitAsRequired( + type_node, type_id, SemanticsNodeId::BuiltinTypeType); + + auto [name_node, name_id] = context.node_stack().PopForParseNodeAndNameId( + ParseNodeKind::DesignatedName); + + context.AddNode( + SemanticsNode::StructTypeField::Make(name_node, cast_type_id, name_id)); + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleStructFieldUnknown(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleStructFieldUnknown"); +} + +auto SemanticsHandleStructFieldValue(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [value_parse_node, value_node_id] = + context.node_stack().PopForParseNodeAndNodeId(); + auto [_, name_id] = context.node_stack().PopForParseNodeAndNameId( + ParseNodeKind::DesignatedName); + + // Store the name for the type. + auto type_block_id = context.args_type_info_stack().PeekForAdd(); + context.semantics().AddNode( + type_block_id, + SemanticsNode::StructTypeField::Make( + parse_node, context.semantics().GetNode(value_node_id).type_id(), + name_id)); + + // Push the value back on the stack as an argument. + context.node_stack().Push(parse_node, value_node_id); + return true; +} + +auto SemanticsHandleStructLiteral(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/true, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + + context.PopScope(); + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + auto type_block_id = context.args_type_info_stack().Pop(); + + // Special-case `{}`. + if (refs_id == SemanticsNodeBlockId::Empty) { + context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinEmptyStruct); + return true; + } + + // Construct a type for the literal. Each field is one node, so ir_id and + // refs_id match. + auto refs = context.semantics().GetNodeBlock(refs_id); + auto type_id = context.AddNode(SemanticsNode::StructType::Make( + parse_node, type_block_id, type_block_id)); + + auto value_id = context.AddNode( + SemanticsNode::StructValue::Make(parse_node, type_id, ir_id, refs_id)); + context.node_stack().Push(parse_node, value_id); + return true; +} + +auto SemanticsHandleStructLiteralOrStructTypeLiteralStart( + SemanticsContext& context, ParseTree::Node parse_node) -> bool { + context.PushScope(); + context.node_stack().Push(parse_node); + // At this point we aren't sure whether this will be a value or type literal, + // so we push onto args irrespective. It just won't be used for a type + // literal. + context.args_type_info_stack().Push(); + context.ParamOrArgStart(); + return true; +} + +auto SemanticsHandleStructTypeLiteral(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/false, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + + context.PopScope(); + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + // This is only used for value literals. + context.args_type_info_stack().Pop(); + + CARBON_CHECK(refs_id != SemanticsNodeBlockId::Empty) + << "{} is handled by StructLiteral."; + + auto type_id = context.AddNode( + SemanticsNode::StructType::Make(parse_node, ir_id, refs_id)); + context.node_stack().Push(parse_node, type_id); + return true; +} + +auto SemanticsHandleTemplate(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleTemplate"); +} + +auto SemanticsHandleTupleLiteral(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleTupleLiteral"); +} + +auto SemanticsHandleTupleLiteralComma(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleTupleLiteralComma"); +} + +auto SemanticsHandleVariableDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [last_parse_node, last_node_id] = + context.node_stack().PopForParseNodeAndNodeId(); + + if (context.parse_tree().node_kind(last_parse_node) != + ParseNodeKind::PatternBinding) { + auto storage_id = + context.node_stack().PopForNodeId(ParseNodeKind::VariableInitializer); + + auto binding = context.node_stack().PopForParseNodeAndNameId( + ParseNodeKind::PatternBinding); + + // Restore the name now that the initializer is complete. + context.ReaddNameToLookup(binding.second, storage_id); + + auto cast_value_id = context.ImplicitAsRequired( + parse_node, last_node_id, + context.semantics().GetNode(storage_id).type_id()); + context.AddNode(SemanticsNode::Assign::Make( + parse_node, context.semantics().GetNode(cast_value_id).type_id(), + storage_id, cast_value_id)); + } + + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::VariableIntroducer); + context.node_stack().Push(parse_node); + + return true; +} + +auto SemanticsHandleVariableIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // No action, just a bracketing node. + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleVariableInitializer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto storage_id = context.TempRemoveLatestNameFromLookup(); + context.node_stack().Push(parse_node, storage_id); + return true; +} + +auto SemanticsHandleWhileCondition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleWhileCondition"); +} + +auto SemanticsHandleWhileConditionStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleWhileConditionStart"); +} + +auto SemanticsHandleWhileStatement(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleWhileStatement"); +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index 7389350fd8578..7e3af85b35b3f 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -5,10 +5,11 @@ #include "toolchain/semantics/semantics_ir.h" #include "common/check.h" +#include "toolchain/common/pretty_stack_trace_function.h" #include "toolchain/parser/parse_tree_node_location_translator.h" #include "toolchain/semantics/semantics_builtin_kind.h" +#include "toolchain/semantics/semantics_context.h" #include "toolchain/semantics/semantics_node.h" -#include "toolchain/semantics/semantics_parse_tree_handler.h" namespace Carbon { @@ -52,8 +53,37 @@ auto SemanticsIR::MakeFromParseTree(const SemanticsIR& builtin_ir, ParseTreeNodeLocationTranslator translator(&tokens, &parse_tree); ErrorTrackingDiagnosticConsumer err_tracker(consumer); DiagnosticEmitter emitter(translator, err_tracker); - SemanticsParseTreeHandler(tokens, emitter, parse_tree, semantics, vlog_stream) - .Build(); + + SemanticsContext context(tokens, emitter, parse_tree, semantics, vlog_stream); + PrettyStackTraceFunction context_dumper( + [&](llvm::raw_ostream& output) { context.PrintForStackDump(output); }); + + // Add a block for the ParseTree. + context.node_block_stack().Push(); + context.PushScope(); + + // Loops over all nodes in the tree. On some errors, this may return early, + // for example if an unrecoverable state is encountered. + for (auto parse_node : parse_tree.postorder()) { + switch (auto parse_kind = parse_tree.node_kind(parse_node)) { +#define CARBON_PARSE_NODE_KIND(Name) \ + case ParseNodeKind::Name: { \ + if (!SemanticsHandle##Name(context, parse_node)) { \ + semantics.has_errors_ = true; \ + return semantics; \ + } \ + break; \ + } +#include "toolchain/parser/parse_node_kind.def" + } + } + + // Pop information for the file-level scope. + semantics.top_node_block_id_ = context.node_block_stack().Pop(); + context.PopScope(); + + context.VerifyOnFinish(); + semantics.has_errors_ = err_tracker.seen_error(); return semantics; } diff --git a/toolchain/semantics/semantics_ir.h b/toolchain/semantics/semantics_ir.h index 9a717908b13f0..ab213df5ddc8f 100644 --- a/toolchain/semantics/semantics_ir.h +++ b/toolchain/semantics/semantics_ir.h @@ -10,10 +10,6 @@ #include "toolchain/parser/parse_tree.h" #include "toolchain/semantics/semantics_node.h" -namespace Carbon::Testing { -class SemanticsIRForTest; -} // namespace Carbon::Testing - namespace Carbon { // A call. @@ -84,57 +80,6 @@ class SemanticsIR { } auto Print(llvm::raw_ostream& out, bool include_builtins) const -> void; - // Returns the requested callable. - auto GetCallable(SemanticsCallableId callable_id) const -> SemanticsCallable { - return callables_[callable_id.index]; - } - - // Returns the requested integer literal. - auto GetIntegerLiteral(SemanticsIntegerLiteralId int_id) const - -> const llvm::APInt& { - return integer_literals_[int_id.index]; - } - - // Returns the requested node. - auto GetNode(SemanticsNodeId node_id) const -> SemanticsNode { - return nodes_[node_id.index]; - } - - // Returns the requested node block. - auto GetNodeBlock(SemanticsNodeBlockId block_id) const - -> const llvm::SmallVector& { - return node_blocks_[block_id.index]; - } - - // Returns the requested real literal. - auto GetRealLiteral(SemanticsRealLiteralId int_id) const - -> const SemanticsRealLiteral& { - return real_literals_[int_id.index]; - } - - // Returns the requested string. - auto GetString(SemanticsStringId string_id) const -> llvm::StringRef { - return strings_[string_id.index]; - } - - auto nodes_size() const -> int { return nodes_.size(); } - - auto top_node_block_id() const -> SemanticsNodeBlockId { - return top_node_block_id_; - } - - // Returns true if there were errors creating the semantics IR. - auto has_errors() const -> bool { return has_errors_; } - - private: - friend class SemanticsParseTreeHandler; - - explicit SemanticsIR(const SemanticsIR* builtin_ir) - : cross_reference_irs_({builtin_ir == nullptr ? this : builtin_ir}) { - // For SemanticsNodeBlockId::Empty. - node_blocks_.resize(1); - } - // Adds a call, returning an ID to reference it. auto AddCall(SemanticsCall call) -> SemanticsCallId { SemanticsCallId id(calls_.size()); @@ -149,6 +94,11 @@ class SemanticsIR { return id; } + // Returns the requested callable. + auto GetCallable(SemanticsCallableId callable_id) const -> SemanticsCallable { + return callables_[callable_id.index]; + } + // Adds an integer literal, returning an ID to reference it. auto AddIntegerLiteral(llvm::APInt integer_literal) -> SemanticsIntegerLiteralId { @@ -157,6 +107,12 @@ class SemanticsIR { return id; } + // Returns the requested integer literal. + auto GetIntegerLiteral(SemanticsIntegerLiteralId int_id) const + -> const llvm::APInt& { + return integer_literals_[int_id.index]; + } + // Adds a node to a specified block, returning an ID to reference the node. auto AddNode(SemanticsNodeBlockId block_id, SemanticsNode node) -> SemanticsNodeId { @@ -166,14 +122,18 @@ class SemanticsIR { return node_id; } - // Adds an empty new node block, returning an ID to reference it and add - // items. - auto AddNodeBlock() -> SemanticsNodeBlockId { - SemanticsNodeBlockId id(node_blocks_.size()); - node_blocks_.resize(node_blocks_.size() + 1); - return id; + // Returns the requested node. + auto GetNode(SemanticsNodeId node_id) const -> SemanticsNode { + return nodes_[node_id.index]; } + // Returns the requested node block. + auto GetNodeBlock(SemanticsNodeBlockId block_id) const + -> const llvm::SmallVector& { + return node_blocks_[block_id.index]; + } + + // Returns the requested node block. auto GetNodeBlock(SemanticsNodeBlockId block_id) -> llvm::SmallVector& { return node_blocks_[block_id.index]; @@ -187,6 +147,12 @@ class SemanticsIR { return id; } + // Returns the requested real literal. + auto GetRealLiteral(SemanticsRealLiteralId int_id) const + -> const SemanticsRealLiteral& { + return real_literals_[int_id.index]; + } + // Adds an string, returning an ID to reference it. auto AddString(llvm::StringRef str) -> SemanticsStringId { // If the string has already been stored, return the corresponding ID. @@ -201,6 +167,11 @@ class SemanticsIR { return id; } + // Returns the requested string. + auto GetString(SemanticsStringId string_id) const -> llvm::StringRef { + return strings_[string_id.index]; + } + // Returns an ID for the string if it's previously been stored. auto GetStringID(llvm::StringRef str) -> std::optional { auto str_find = string_to_id_.find(str); @@ -213,6 +184,27 @@ class SemanticsIR { // Produces a string version of a node. auto StringifyNode(SemanticsNodeId node_id) -> std::string; + auto nodes_size() const -> int { return nodes_.size(); } + + // The node blocks, for direct mutation. + auto node_blocks() -> llvm::SmallVector>& { + return node_blocks_; + } + + auto top_node_block_id() const -> SemanticsNodeBlockId { + return top_node_block_id_; + } + + // Returns true if there were errors creating the semantics IR. + auto has_errors() const -> bool { return has_errors_; } + + private: + explicit SemanticsIR(const SemanticsIR* builtin_ir) + : cross_reference_irs_({builtin_ir == nullptr ? this : builtin_ir}) { + // For SemanticsNodeBlockId::Empty. + node_blocks_.resize(1); + } + bool has_errors_ = false; // Storage for call objects. diff --git a/toolchain/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp deleted file mode 100644 index 9b69771503653..0000000000000 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ /dev/null @@ -1,1249 +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 "toolchain/semantics/semantics_parse_tree_handler.h" - -#include -#include - -#include "common/vlog.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "toolchain/diagnostics/diagnostic_kind.h" -#include "toolchain/lexer/token_kind.h" -#include "toolchain/lexer/tokenized_buffer.h" -#include "toolchain/parser/parse_node_kind.h" -#include "toolchain/semantics/semantics_ir.h" -#include "toolchain/semantics/semantics_node.h" -#include "toolchain/semantics/semantics_node_block_stack.h" - -namespace Carbon { - -CARBON_DIAGNOSTIC(SemanticsTodo, Error, "Semantics TODO: {0}", std::string); - -class PrettyStackTraceFunction : public llvm::PrettyStackTraceEntry { - public: - explicit PrettyStackTraceFunction(std::function fn) - : fn_(std::move(fn)) {} - ~PrettyStackTraceFunction() override = default; - - auto print(llvm::raw_ostream& output) const -> void override { fn_(output); } - - private: - const std::function fn_; -}; - -auto SemanticsParseTreeHandler::Build() -> void { - PrettyStackTraceFunction pretty_node_stack([&](llvm::raw_ostream& output) { - node_stack_.PrintForStackDump(output); - }); - PrettyStackTraceFunction pretty_node_block_stack( - [&](llvm::raw_ostream& output) { - node_block_stack_.PrintForStackDump(output); - }); - - // Add a block for the ParseTree. - node_block_stack_.Push(); - PushScope(); - - // Loops over all nodes in the tree. On some errors, this may return early, - // for example if an unrecoverable state is encountered. - for (auto parse_node : parse_tree_->postorder()) { - switch (auto parse_kind = parse_tree_->node_kind(parse_node)) { -#define CARBON_PARSE_NODE_KIND(Name) \ - case ParseNodeKind::Name: { \ - if (!Handle##Name(parse_node)) { \ - return; \ - } \ - break; \ - } -#include "toolchain/parser/parse_node_kind.def" - } - } - - // Pop information for the file-level scope. - semantics_->top_node_block_id_ = node_block_stack_.Pop(); - PopScope(); - - // Information in all the various context objects should be cleaned up as - // various pieces of context go out of scope. At this point, nothing should - // remain. - // node_stack_ will still contain top-level entities. - CARBON_CHECK(name_lookup_.empty()) << name_lookup_.size(); - CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size(); - CARBON_CHECK(node_block_stack_.empty()) << node_block_stack_.size(); - CARBON_CHECK(params_or_args_stack_.empty()) << params_or_args_stack_.size(); -} - -auto SemanticsParseTreeHandler::AddNode(SemanticsNode node) -> SemanticsNodeId { - auto block = node_block_stack_.PeekForAdd(); - CARBON_VLOG() << "AddNode " << block << ": " << node << "\n"; - return semantics_->AddNode(block, node); -} - -auto SemanticsParseTreeHandler::AddNodeAndPush(ParseTree::Node parse_node, - SemanticsNode node) -> void { - auto node_id = AddNode(node); - node_stack_.Push(parse_node, node_id); -} - -auto SemanticsParseTreeHandler::AddNameToLookup(ParseTree::Node name_node, - SemanticsStringId name_id, - SemanticsNodeId target_id) - -> void { - auto [it, inserted] = current_scope().names.insert(name_id); - if (inserted) { - name_lookup_[name_id].push_back(target_id); - } else { - CARBON_DIAGNOSTIC(NameRedefined, Error, "Redefining {0} in the same scope.", - llvm::StringRef); - CARBON_DIAGNOSTIC(PreviousDefinition, Note, "Previous definition is here."); - auto prev_def_id = name_lookup_[name_id].back(); - auto prev_def = semantics_->GetNode(prev_def_id); - - emitter_->Build(name_node, NameRedefined, semantics_->GetString(name_id)) - .Note(prev_def.parse_node(), PreviousDefinition) - .Emit(); - } -} - -auto SemanticsParseTreeHandler::BindName(ParseTree::Node name_node, - SemanticsNodeId type_id, - SemanticsNodeId target_id) - -> SemanticsStringId { - CARBON_CHECK(parse_tree_->node_kind(name_node) == ParseNodeKind::DeclaredName) - << parse_tree_->node_kind(name_node); - auto name_str = parse_tree_->GetNodeText(name_node); - auto name_id = semantics_->AddString(name_str); - - AddNode( - SemanticsNode::BindName::Make(name_node, type_id, name_id, target_id)); - AddNameToLookup(name_node, name_id, target_id); - return name_id; -} - -auto SemanticsParseTreeHandler::PushScope() -> void { - scope_stack_.push_back({}); -} - -auto SemanticsParseTreeHandler::PopScope() -> void { - auto scope = scope_stack_.pop_back_val(); - for (const auto& str_id : scope.names) { - auto it = name_lookup_.find(str_id); - if (it->second.size() == 1) { - // Erase names that no longer resolve. - name_lookup_.erase(it); - } else { - it->second.pop_back(); - } - } -} - -auto SemanticsParseTreeHandler::ImplicitAsForArgs( - SemanticsNodeBlockId /*arg_ir_id*/, SemanticsNodeBlockId arg_refs_id, - ParseTree::Node param_parse_node, SemanticsNodeBlockId param_refs_id, - DiagnosticEmitter::DiagnosticBuilder* diagnostic) -> bool { - // If both arguments and parameters are empty, return quickly. Otherwise, - // we'll fetch both so that errors are consistent. - if (arg_refs_id == SemanticsNodeBlockId::Empty && - param_refs_id == SemanticsNodeBlockId::Empty) { - return true; - } - - auto arg_refs = semantics_->GetNodeBlock(arg_refs_id); - auto param_refs = semantics_->GetNodeBlock(param_refs_id); - - // If sizes mismatch, fail early. - if (arg_refs.size() != param_refs.size()) { - CARBON_CHECK(diagnostic != nullptr) << "Should have validated first"; - CARBON_DIAGNOSTIC(CallArgCountMismatch, Note, - "Callable cannot be used: Received {0} argument(s), but " - "require {1} argument(s).", - int, int); - diagnostic->Note(param_parse_node, CallArgCountMismatch, arg_refs.size(), - param_refs.size()); - return false; - } - - // Check type conversions per-element. - // TODO: arg_ir_id is passed so that implicit conversions can be inserted. - // It's currently not supported, but will be needed. - for (size_t i = 0; i < arg_refs.size(); ++i) { - auto value_id = arg_refs[i]; - auto as_type_id = semantics_->GetNode(param_refs[i]).type_id(); - if (ImplicitAsImpl(value_id, as_type_id, - diagnostic == nullptr ? &value_id : nullptr) == - ImplicitAsKind::Incompatible) { - CARBON_CHECK(diagnostic != nullptr) << "Should have validated first"; - CARBON_DIAGNOSTIC(CallArgTypeMismatch, Note, - "Callable cannot be used: Cannot implicityly convert " - "argument {0} from `{1}` to `{2}`.", - size_t, std::string, std::string); - diagnostic->Note( - param_parse_node, CallArgTypeMismatch, i, - semantics_->StringifyNode(semantics_->GetNode(value_id).type_id()), - semantics_->StringifyNode(as_type_id)); - return false; - } - } - - return true; -} - -auto SemanticsParseTreeHandler::ImplicitAsRequired(ParseTree::Node parse_node, - SemanticsNodeId value_id, - SemanticsNodeId as_type_id) - -> SemanticsNodeId { - SemanticsNodeId output_value_id = value_id; - if (ImplicitAsImpl(value_id, as_type_id, &output_value_id) == - ImplicitAsKind::Incompatible) { - // Only error when the system is trying to use the result. - CARBON_DIAGNOSTIC(ImplicitAsConversionFailure, Error, - "Cannot implicitly convert from `{0}` to `{1}`.", - std::string, std::string); - emitter_ - ->Build( - parse_node, ImplicitAsConversionFailure, - semantics_->StringifyNode(semantics_->GetNode(value_id).type_id()), - semantics_->StringifyNode(as_type_id)) - .Emit(); - } - return output_value_id; -} - -auto SemanticsParseTreeHandler::ImplicitAsImpl(SemanticsNodeId value_id, - SemanticsNodeId as_type_id, - SemanticsNodeId* output_value_id) - -> ImplicitAsKind { - // Start by making sure both sides are valid. If any part is invalid, the - // result is invalid and we shouldn't error. - if (value_id == SemanticsNodeId::BuiltinInvalidType) { - // If the value is invalid, we can't do much, but do "succeed". - return ImplicitAsKind::Identical; - } - auto value_type_id = semantics_->GetNode(value_id).type_id(); - if (value_type_id == SemanticsNodeId::BuiltinInvalidType) { - return ImplicitAsKind::Identical; - } - if (as_type_id == SemanticsNodeId::BuiltinInvalidType) { - // Although the target type is invalid, this still changes the value. - if (output_value_id != nullptr) { - *output_value_id = SemanticsNodeId::BuiltinInvalidType; - } - return ImplicitAsKind::Compatible; - } - - if (value_type_id == as_type_id) { - // Type doesn't need to change. - return ImplicitAsKind::Identical; - } - - // When converting to a Type, there are some automatic conversions that can be - // done. - if (as_type_id == SemanticsNodeId::BuiltinTypeType) { - if (value_id == SemanticsNodeId::BuiltinEmptyTuple) { - if (output_value_id != nullptr) { - *output_value_id = SemanticsNodeId::BuiltinEmptyTupleType; - } - return ImplicitAsKind::Compatible; - } - if (value_id == SemanticsNodeId::BuiltinEmptyStruct) { - if (output_value_id != nullptr) { - *output_value_id = SemanticsNodeId::BuiltinEmptyStructType; - } - return ImplicitAsKind::Compatible; - } - } - - auto value_type = semantics_->GetNode(value_type_id); - auto as_type = semantics_->GetNode(as_type_id); - if (CanImplicitAsStruct(value_type, as_type)) { - // Under the current implementation, struct types are only allowed to - // ImplicitAs when they're equivalent. What's really missing is type - // consolidation such that this would fall under the above `value_type_id == - // as_type_id` case. In the future, this will need to handle actual - // conversions. - return ImplicitAsKind::Identical; - } - - if (output_value_id != nullptr) { - *output_value_id = SemanticsNodeId::BuiltinInvalidType; - } - return ImplicitAsKind::Incompatible; -} - -auto SemanticsParseTreeHandler::CanImplicitAsStruct(SemanticsNode value_type, - SemanticsNode as_type) - -> bool { - if (value_type.kind() != SemanticsNodeKind::StructType || - as_type.kind() != SemanticsNodeKind::StructType) { - return false; - } - auto value_type_refs = - semantics_->GetNodeBlock(value_type.GetAsStructType().second); - auto as_type_refs = - semantics_->GetNodeBlock(as_type.GetAsStructType().second); - if (value_type_refs.size() != as_type_refs.size()) { - return false; - } - - for (int i = 0; i < static_cast(value_type_refs.size()); ++i) { - auto value_type_field = semantics_->GetNode(value_type_refs[i]); - auto as_type_field = semantics_->GetNode(as_type_refs[i]); - if (value_type_field.type_id() != as_type_field.type_id() || - value_type_field.GetAsStructTypeField() != - as_type_field.GetAsStructTypeField()) { - return false; - } - } - return true; -} - -auto SemanticsParseTreeHandler::ParamOrArgStart() -> void { - params_or_args_stack_.Push(); - node_block_stack_.Push(); -} - -auto SemanticsParseTreeHandler::ParamOrArgComma(bool for_args) -> void { - ParamOrArgSave(for_args); -} - -auto SemanticsParseTreeHandler::ParamOrArgEnd(bool for_args, - ParseNodeKind start_kind) - -> std::pair { - if (parse_tree_->node_kind(node_stack_.PeekParseNode()) != start_kind) { - ParamOrArgSave(for_args); - } - return {node_block_stack_.Pop(), params_or_args_stack_.Pop()}; -} - -auto SemanticsParseTreeHandler::ParamOrArgSave(bool for_args) -> void { - SemanticsNodeId param_or_arg_id = SemanticsNodeId::Invalid; - if (for_args) { - // For an argument, we add a stub reference to the expression on the top of - // the stack. There may not be anything on the IR prior to this. - auto [entry_parse_node, entry_node_id] = - node_stack_.PopForParseNodeAndNodeId(); - param_or_arg_id = AddNode(SemanticsNode::StubReference::Make( - entry_parse_node, semantics_->GetNode(entry_node_id).type_id(), - entry_node_id)); - } else { - // For a parameter, there should always be something in the IR. - node_stack_.PopAndIgnore(); - auto ir_id = node_block_stack_.Peek(); - CARBON_CHECK(ir_id.is_valid()); - auto& ir = semantics_->GetNodeBlock(ir_id); - CARBON_CHECK(!ir.empty()) << "Should have had a param"; - param_or_arg_id = ir.back(); - } - - // Save the param or arg ID. - auto& params_or_args = - semantics_->GetNodeBlock(params_or_args_stack_.PeekForAdd()); - params_or_args.push_back(param_or_arg_id); -} - -auto SemanticsParseTreeHandler::HandleAddress(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleAddress"); - return false; -} - -auto SemanticsParseTreeHandler::HandleBreakStatement(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleBreakStatement"); - return false; -} - -auto SemanticsParseTreeHandler::HandleBreakStatementStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleBreakStatementStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleCallExpression(ParseTree::Node parse_node) - -> bool { - auto [ir_id, refs_id] = - ParamOrArgEnd(/*for_args=*/true, ParseNodeKind::CallExpressionStart); - - // TODO: Convert to call expression. - auto [call_expr_parse_node, name_id] = - node_stack_.PopForParseNodeAndNodeId(ParseNodeKind::CallExpressionStart); - auto name_node = semantics_->GetNode(name_id); - if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) { - // TODO: Work on error. - emitter_->Emit(parse_node, SemanticsTodo, "Not a callable name"); - node_stack_.Push(parse_node, name_id); - return true; - } - - auto [_, callable_id] = name_node.GetAsFunctionDeclaration(); - auto callable = semantics_->GetCallable(callable_id); - - CARBON_DIAGNOSTIC(NoMatchingCall, Error, "No matching callable was found."); - auto diagnostic = emitter_->Build(call_expr_parse_node, NoMatchingCall); - if (!ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), - callable.param_refs_id, &diagnostic)) { - diagnostic.Emit(); - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinInvalidType); - return true; - } - - CARBON_CHECK(ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), - callable.param_refs_id, - /*diagnostic=*/nullptr)); - - auto call_id = semantics_->AddCall({ir_id, refs_id}); - // TODO: Propagate return types from callable. - auto call_node_id = AddNode(SemanticsNode::Call::Make( - call_expr_parse_node, callable.return_type_id, call_id, callable_id)); - - node_stack_.Push(parse_node, call_node_id); - return true; -} - -auto SemanticsParseTreeHandler::HandleCallExpressionComma( - ParseTree::Node /*parse_node*/) -> bool { - ParamOrArgComma(/*for_args=*/true); - return true; -} - -auto SemanticsParseTreeHandler::HandleCallExpressionStart( - ParseTree::Node parse_node) -> bool { - auto name_id = node_stack_.PopForNodeId(ParseNodeKind::NameReference); - node_stack_.Push(parse_node, name_id); - ParamOrArgStart(); - return true; -} - -auto SemanticsParseTreeHandler::HandleClassDeclaration( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleClassDeclaration"); - return false; -} - -auto SemanticsParseTreeHandler::HandleClassDefinition( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleClassDefinition"); - return false; -} - -auto SemanticsParseTreeHandler::HandleClassDefinitionStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleClassDefinitionStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleClassIntroducer( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleClassIntroducer"); - return false; -} - -auto SemanticsParseTreeHandler::HandleCodeBlock(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleCodeBlock"); - return false; -} - -auto SemanticsParseTreeHandler::HandleCodeBlockStart(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleCodeBlockStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleContinueStatement( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleContinueStatement"); - return false; -} - -auto SemanticsParseTreeHandler::HandleContinueStatementStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleContinueStatementStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleDeclaredName(ParseTree::Node parse_node) - -> bool { - // The parent is responsible for binding the name. - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleDeducedParameterList( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleDeducedParameterList"); - return false; -} - -auto SemanticsParseTreeHandler::HandleDeducedParameterListStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleDeducedParameterListStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleDesignatedName(ParseTree::Node parse_node) - -> bool { - auto name_str = parse_tree_->GetNodeText(parse_node); - auto name_id = semantics_->AddString(name_str); - // The parent is responsible for binding the name. - node_stack_.Push(parse_node, name_id); - return true; -} - -auto SemanticsParseTreeHandler::HandleDesignatorExpression( - ParseTree::Node parse_node) -> bool { - auto [_, name_id] = - node_stack_.PopForParseNodeAndNameId(ParseNodeKind::DesignatedName); - - auto base_id = node_stack_.PopForNodeId(); - auto base = semantics_->GetNode(base_id); - auto base_type = semantics_->GetNode(base.type_id()); - - switch (base_type.kind()) { - case SemanticsNodeKind::StructType: { - auto refs = semantics_->GetNodeBlock(base_type.GetAsStructType().second); - // TODO: Do we need to optimize this with a lookup table for O(1)? - for (int i = 0; i < static_cast(refs.size()); ++i) { - auto ref = semantics_->GetNode(refs[i]); - if (name_id == ref.GetAsStructTypeField()) { - AddNodeAndPush(parse_node, SemanticsNode::StructMemberAccess::Make( - parse_node, ref.type_id(), base_id, - SemanticsMemberIndex(i))); - return true; - } - } - CARBON_DIAGNOSTIC(DesignatorExpressionNameNotFound, Error, - "Type `{0}` does not have a member `{1}`.", std::string, - llvm::StringRef); - emitter_->Emit(parse_node, DesignatorExpressionNameNotFound, - semantics_->StringifyNode(base.type_id()), - semantics_->GetString(name_id)); - break; - } - default: { - CARBON_DIAGNOSTIC(DesignatorExpressionUnsupported, Error, - "Type `{0}` does not support designator expressions.", - std::string); - emitter_->Emit(parse_node, DesignatorExpressionUnsupported, - semantics_->StringifyNode(base.type_id())); - break; - } - } - - // Should only be reached on error. - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinInvalidType); - return true; -} - -auto SemanticsParseTreeHandler::HandleEmptyDeclaration( - ParseTree::Node parse_node) -> bool { - // Empty declarations have no actions associated, but we still balance the - // tree. - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleExpressionStatement( - ParseTree::Node parse_node) -> bool { - // Pop the expression without investigating its contents. - // TODO: This will probably eventually need to do some "do not discard" - // analysis. - node_stack_.PopAndDiscardId(); - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleFileEnd(ParseTree::Node /*parse_node*/) - -> bool { - // Do nothing, no need to balance this node. - return true; -} - -auto SemanticsParseTreeHandler::HandleForHeader(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleForHeader"); - return false; -} - -auto SemanticsParseTreeHandler::HandleForHeaderStart(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleForHeaderStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleForIn(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleForIn"); - return false; -} - -auto SemanticsParseTreeHandler::HandleForStatement(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleForStatement"); - return false; -} - -auto SemanticsParseTreeHandler::HandleFunctionDeclaration( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleFunctionDeclaration"); - return false; -} - -auto SemanticsParseTreeHandler::HandleFunctionDefinition( - ParseTree::Node parse_node) -> bool { - // Merges code block children up under the FunctionDefinitionStart. - while (parse_tree_->node_kind(node_stack_.PeekParseNode()) != - ParseNodeKind::FunctionDefinitionStart) { - node_stack_.PopAndIgnore(); - } - auto decl_id = - node_stack_.PopForNodeId(ParseNodeKind::FunctionDefinitionStart); - - return_scope_stack_.pop_back(); - PopScope(); - auto block_id = node_block_stack_.Pop(); - AddNode( - SemanticsNode::FunctionDefinition::Make(parse_node, decl_id, block_id)); - node_stack_.Push(parse_node); - - return true; -} - -auto SemanticsParseTreeHandler::HandleFunctionDefinitionStart( - ParseTree::Node parse_node) -> bool { - SemanticsNodeId return_type_id = SemanticsNodeId::Invalid; - if (parse_tree_->node_kind(node_stack_.PeekParseNode()) == - ParseNodeKind::ReturnType) { - return_type_id = node_stack_.PopForNodeId(ParseNodeKind::ReturnType); - } - node_stack_.PopForSoloParseNode(ParseNodeKind::ParameterList); - auto [param_ir_id, param_refs_id] = finished_params_stack_.pop_back_val(); - auto name_node = node_stack_.PopForSoloParseNode(ParseNodeKind::DeclaredName); - auto fn_node = - node_stack_.PopForSoloParseNode(ParseNodeKind::FunctionIntroducer); - - auto name_str = parse_tree_->GetNodeText(name_node); - auto name_id = semantics_->AddString(name_str); - - auto callable_id = - semantics_->AddCallable({.param_ir_id = param_ir_id, - .param_refs_id = param_refs_id, - .return_type_id = return_type_id}); - auto decl_id = AddNode( - SemanticsNode::FunctionDeclaration::Make(fn_node, name_id, callable_id)); - AddNameToLookup(name_node, name_id, decl_id); - - node_block_stack_.Push(); - PushScope(); - return_scope_stack_.push_back(decl_id); - node_stack_.Push(parse_node, decl_id); - - return true; -} - -auto SemanticsParseTreeHandler::HandleFunctionIntroducer( - ParseTree::Node parse_node) -> bool { - // No action, just a bracketing node. - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleGenericPatternBinding( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "GenericPatternBinding"); - return false; -} - -auto SemanticsParseTreeHandler::HandleIfCondition(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleIfCondition"); - return false; -} - -auto SemanticsParseTreeHandler::HandleIfConditionStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleIfConditionStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleIfStatement(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleIfStatement"); - return false; -} - -auto SemanticsParseTreeHandler::HandleIfStatementElse( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleIfStatementElse"); - return false; -} - -auto SemanticsParseTreeHandler::HandleInfixOperator(ParseTree::Node parse_node) - -> bool { - auto rhs_id = node_stack_.PopForNodeId(); - auto lhs_id = node_stack_.PopForNodeId(); - - // TODO: This should search for a compatible interface. For now, it's a very - // trivial check of validity on the operation. - lhs_id = ImplicitAsRequired(parse_node, lhs_id, - semantics_->GetNode(rhs_id).type_id()); - - // Figure out the operator for the token. - auto token = parse_tree_->node_token(parse_node); - switch (auto token_kind = tokens_->GetKind(token)) { - case TokenKind::Plus: - AddNodeAndPush(parse_node, - SemanticsNode::BinaryOperatorAdd::Make( - parse_node, semantics_->GetNode(lhs_id).type_id(), - lhs_id, rhs_id)); - break; - default: - emitter_->Emit(parse_node, SemanticsTodo, - llvm::formatv("Handle {0}", token_kind)); - return false; - } - - return true; -} - -auto SemanticsParseTreeHandler::HandleInterfaceDeclaration( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleInterfaceDeclaration"); - return false; -} - -auto SemanticsParseTreeHandler::HandleInterfaceDefinition( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleInterfaceDefinition"); - return false; -} - -auto SemanticsParseTreeHandler::HandleInterfaceDefinitionStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleInterfaceDefinitionStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleInterfaceIntroducer( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleInterfaceIntroducer"); - return false; -} - -auto SemanticsParseTreeHandler::HandleInvalidParse(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleInvalidParse"); - return false; -} - -auto SemanticsParseTreeHandler::HandleLiteral(ParseTree::Node parse_node) - -> bool { - auto token = parse_tree_->node_token(parse_node); - switch (auto token_kind = tokens_->GetKind(token)) { - case TokenKind::IntegerLiteral: { - auto id = - semantics_->AddIntegerLiteral(tokens_->GetIntegerLiteral(token)); - AddNodeAndPush(parse_node, - SemanticsNode::IntegerLiteral::Make(parse_node, id)); - break; - } - case TokenKind::RealLiteral: { - auto token_value = tokens_->GetRealLiteral(token); - auto id = - semantics_->AddRealLiteral({.mantissa = token_value.Mantissa(), - .exponent = token_value.Exponent(), - .is_decimal = token_value.IsDecimal()}); - AddNodeAndPush(parse_node, - SemanticsNode::RealLiteral::Make(parse_node, id)); - break; - } - case TokenKind::StringLiteral: { - auto id = semantics_->AddString(tokens_->GetStringLiteral(token)); - AddNodeAndPush(parse_node, - SemanticsNode::StringLiteral::Make(parse_node, id)); - break; - } - case TokenKind::IntegerTypeLiteral: { - auto text = tokens_->GetTokenText(token); - if (text != "i32") { - emitter_->Emit(parse_node, SemanticsTodo, - "Currently only i32 is allowed"); - return false; - } - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinIntegerType); - break; - } - case TokenKind::FloatingPointTypeLiteral: { - auto text = tokens_->GetTokenText(token); - if (text != "f64") { - emitter_->Emit(parse_node, SemanticsTodo, - "Currently only f64 is allowed"); - return false; - } - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinFloatingPointType); - break; - } - case TokenKind::StringTypeLiteral: { - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinStringType); - break; - } - default: { - emitter_->Emit(parse_node, SemanticsTodo, - llvm::formatv("Handle {0}", token_kind)); - return false; - } - } - - return true; -} - -auto SemanticsParseTreeHandler::HandleNameReference(ParseTree::Node parse_node) - -> bool { - auto name_str = parse_tree_->GetNodeText(parse_node); - - auto name_not_found = [&] { - CARBON_DIAGNOSTIC(NameNotFound, Error, "Name {0} not found", - llvm::StringRef); - emitter_->Emit(parse_node, NameNotFound, name_str); - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinInvalidType); - }; - - auto name_id = semantics_->GetStringID(name_str); - if (!name_id) { - name_not_found(); - return true; - } - - auto it = name_lookup_.find(*name_id); - if (it == name_lookup_.end()) { - name_not_found(); - return true; - } - CARBON_CHECK(!it->second.empty()) << "Should have been erased: " << name_str; - - // TODO: Check for ambiguous lookups. - node_stack_.Push(parse_node, it->second.back()); - - return true; -} - -auto SemanticsParseTreeHandler::HandleNamedConstraintDeclaration( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleNamedConstraintDeclaration"); - return false; -} - -auto SemanticsParseTreeHandler::HandleNamedConstraintDefinition( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleNamedConstraintDefinition"); - return false; -} - -auto SemanticsParseTreeHandler::HandleNamedConstraintDefinitionStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, - "HandleNamedConstraintDefinitionStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleNamedConstraintIntroducer( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleNamedConstraintIntroducer"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePackageApi(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePackageApi"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePackageDirective( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePackageDirective"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePackageImpl(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePackageImpl"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePackageIntroducer( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePackageIntroducer"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePackageLibrary(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePackageLibrary"); - return false; -} - -auto SemanticsParseTreeHandler::HandleParameterList(ParseTree::Node parse_node) - -> bool { - auto [ir_id, refs_id] = - ParamOrArgEnd(/*for_args=*/false, ParseNodeKind::ParameterListStart); - - PopScope(); - node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ParameterListStart); - finished_params_stack_.push_back({ir_id, refs_id}); - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleParameterListComma( - ParseTree::Node /*parse_node*/) -> bool { - ParamOrArgComma(/*for_args=*/false); - return true; -} - -auto SemanticsParseTreeHandler::HandleParameterListStart( - ParseTree::Node parse_node) -> bool { - PushScope(); - node_stack_.Push(parse_node); - ParamOrArgStart(); - return true; -} - -auto SemanticsParseTreeHandler::HandleParenExpression( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleParenExpression"); - return false; -} - -auto SemanticsParseTreeHandler::HandleParenExpressionOrTupleLiteralStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, - "HandleParenExpressionOrTupleLiteralStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePatternBinding(ParseTree::Node parse_node) - -> bool { - auto [type_node, parsed_type_id] = node_stack_.PopForParseNodeAndNodeId(); - SemanticsNodeId cast_type_id = ImplicitAsRequired( - type_node, parsed_type_id, SemanticsNodeId::BuiltinTypeType); - - // Get the name. - auto name_node = node_stack_.PopForSoloParseNode(); - - // Allocate storage, linked to the name for error locations. - auto storage_id = - AddNode(SemanticsNode::VarStorage::Make(name_node, cast_type_id)); - - // Bind the name to storage. - auto name_id = BindName(name_node, cast_type_id, storage_id); - - // If this node's result is used, it'll be for either the name or the - // storage address. The storage address can be found through the name, so we - // push the name. - node_stack_.Push(parse_node, name_id); - - return true; -} - -auto SemanticsParseTreeHandler::HandlePostfixOperator( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePostfixOperator"); - return false; -} - -auto SemanticsParseTreeHandler::HandlePrefixOperator(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandlePrefixOperator"); - return false; -} - -auto SemanticsParseTreeHandler::HandleReturnStatement( - ParseTree::Node parse_node) -> bool { - CARBON_CHECK(!return_scope_stack_.empty()); - const auto& fn_node = semantics_->GetNode(return_scope_stack_.back()); - const auto callable = - semantics_->GetCallable(fn_node.GetAsFunctionDeclaration().second); - - if (parse_tree_->node_kind(node_stack_.PeekParseNode()) == - ParseNodeKind::ReturnStatementStart) { - node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ReturnStatementStart); - - if (callable.return_type_id.is_valid()) { - // TODO: Add a note pointing at the return type's parse node. - CARBON_DIAGNOSTIC(ReturnStatementMissingExpression, Error, - "Must return a {0}.", std::string); - emitter_ - ->Build(parse_node, ReturnStatementMissingExpression, - semantics_->StringifyNode(callable.return_type_id)) - .Emit(); - } - - AddNodeAndPush(parse_node, SemanticsNode::Return::Make(parse_node)); - } else { - auto arg = node_stack_.PopForNodeId(); - node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::ReturnStatementStart); - - if (!callable.return_type_id.is_valid()) { - CARBON_DIAGNOSTIC( - ReturnStatementDisallowExpression, Error, - "No return expression should be provided in this context."); - CARBON_DIAGNOSTIC(ReturnStatementImplicitNote, Note, - "There was no return type provided."); - emitter_->Build(parse_node, ReturnStatementDisallowExpression) - .Note(fn_node.parse_node(), ReturnStatementImplicitNote) - .Emit(); - } else { - arg = ImplicitAsRequired(parse_node, arg, callable.return_type_id); - } - - AddNodeAndPush(parse_node, - SemanticsNode::ReturnExpression::Make( - parse_node, semantics_->GetNode(arg).type_id(), arg)); - } - return true; -} - -auto SemanticsParseTreeHandler::HandleReturnStatementStart( - ParseTree::Node parse_node) -> bool { - // No action, just a bracketing node. - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleReturnType(ParseTree::Node parse_node) - -> bool { - // Propagate the type expression. - auto [type_parse_node, type_node_id] = node_stack_.PopForParseNodeAndNodeId(); - auto cast_node_id = ImplicitAsRequired(type_parse_node, type_node_id, - SemanticsNodeId::BuiltinTypeType); - node_stack_.Push(parse_node, cast_node_id); - return true; -} - -auto SemanticsParseTreeHandler::HandleSelfTypeIdentifier( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleSelfTypeIdentifier"); - return false; -} - -auto SemanticsParseTreeHandler::HandleSelfValueIdentifier( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleSelfValueIdentifier"); - return false; -} - -auto SemanticsParseTreeHandler::HandleStructComma( - ParseTree::Node /*parse_node*/) -> bool { - ParamOrArgComma( - /*for_args=*/parse_tree_->node_kind(node_stack_.PeekParseNode()) != - ParseNodeKind::StructFieldType); - return true; -} - -auto SemanticsParseTreeHandler::HandleStructFieldDesignator( - ParseTree::Node /*parse_node*/) -> bool { - // This leaves the designated name on top because the `.` isn't interesting. - CARBON_CHECK(parse_tree_->node_kind(node_stack_.PeekParseNode()) == - ParseNodeKind::DesignatedName); - return true; -} - -auto SemanticsParseTreeHandler::HandleStructFieldType( - ParseTree::Node parse_node) -> bool { - auto [type_node, type_id] = node_stack_.PopForParseNodeAndNodeId(); - SemanticsNodeId cast_type_id = - ImplicitAsRequired(type_node, type_id, SemanticsNodeId::BuiltinTypeType); - - auto [name_node, name_id] = - node_stack_.PopForParseNodeAndNameId(ParseNodeKind::DesignatedName); - - AddNode( - SemanticsNode::StructTypeField::Make(name_node, cast_type_id, name_id)); - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleStructFieldUnknown( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleStructFieldUnknown"); - return false; -} - -auto SemanticsParseTreeHandler::HandleStructFieldValue( - ParseTree::Node parse_node) -> bool { - auto [value_parse_node, value_node_id] = - node_stack_.PopForParseNodeAndNodeId(); - auto [_, name_id] = - node_stack_.PopForParseNodeAndNameId(ParseNodeKind::DesignatedName); - - // Store the name for the type. - auto type_block_id = args_type_info_stack_.PeekForAdd(); - semantics_->AddNode( - type_block_id, - SemanticsNode::StructTypeField::Make( - parse_node, semantics_->GetNode(value_node_id).type_id(), name_id)); - - // Push the value back on the stack as an argument. - node_stack_.Push(parse_node, value_node_id); - return true; -} - -auto SemanticsParseTreeHandler::HandleStructLiteral(ParseTree::Node parse_node) - -> bool { - auto [ir_id, refs_id] = ParamOrArgEnd( - /*for_args=*/true, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - - PopScope(); - node_stack_.PopAndDiscardSoloParseNode( - ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - auto type_block_id = args_type_info_stack_.Pop(); - - // Special-case `{}`. - if (refs_id == SemanticsNodeBlockId::Empty) { - node_stack_.Push(parse_node, SemanticsNodeId::BuiltinEmptyStruct); - return true; - } - - // Construct a type for the literal. Each field is one node, so ir_id and - // refs_id match. - auto refs = semantics_->GetNodeBlock(refs_id); - auto type_id = AddNode(SemanticsNode::StructType::Make( - parse_node, type_block_id, type_block_id)); - - auto value_id = AddNode( - SemanticsNode::StructValue::Make(parse_node, type_id, ir_id, refs_id)); - node_stack_.Push(parse_node, value_id); - return true; -} - -auto SemanticsParseTreeHandler::HandleStructLiteralOrStructTypeLiteralStart( - ParseTree::Node parse_node) -> bool { - PushScope(); - node_stack_.Push(parse_node); - // At this point we aren't sure whether this will be a value or type literal, - // so we push onto args irrespective. It just won't be used for a type - // literal. - args_type_info_stack_.Push(); - ParamOrArgStart(); - return true; -} - -auto SemanticsParseTreeHandler::HandleStructTypeLiteral( - ParseTree::Node parse_node) -> bool { - auto [ir_id, refs_id] = ParamOrArgEnd( - /*for_args=*/false, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - - PopScope(); - node_stack_.PopAndDiscardSoloParseNode( - ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - // This is only used for value literals. - args_type_info_stack_.Pop(); - - CARBON_CHECK(refs_id != SemanticsNodeBlockId::Empty) - << "{} is handled by StructLiteral."; - - auto type_id = - AddNode(SemanticsNode::StructType::Make(parse_node, ir_id, refs_id)); - node_stack_.Push(parse_node, type_id); - return true; -} - -auto SemanticsParseTreeHandler::HandleTemplate(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleTemplate"); - return false; -} - -auto SemanticsParseTreeHandler::HandleTupleLiteral(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleTupleLiteral"); - return false; -} - -auto SemanticsParseTreeHandler::HandleTupleLiteralComma( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleTupleLiteralComma"); - return false; -} - -auto SemanticsParseTreeHandler::HandleVariableDeclaration( - ParseTree::Node parse_node) -> bool { - auto [last_parse_node, last_node_id] = node_stack_.PopForParseNodeAndNodeId(); - - if (parse_tree_->node_kind(last_parse_node) != - ParseNodeKind::PatternBinding) { - auto storage_id = - node_stack_.PopForNodeId(ParseNodeKind::VariableInitializer); - - auto binding = - node_stack_.PopForParseNodeAndNameId(ParseNodeKind::PatternBinding); - - // Restore the name now that the initializer is complete. - ReaddNameToLookup(binding.second, storage_id); - - auto cast_value_id = ImplicitAsRequired( - parse_node, last_node_id, semantics_->GetNode(storage_id).type_id()); - AddNode(SemanticsNode::Assign::Make( - parse_node, semantics_->GetNode(cast_value_id).type_id(), storage_id, - cast_value_id)); - } - - node_stack_.PopAndDiscardSoloParseNode(ParseNodeKind::VariableIntroducer); - node_stack_.Push(parse_node); - - return true; -} - -auto SemanticsParseTreeHandler::HandleVariableIntroducer( - ParseTree::Node parse_node) -> bool { - // No action, just a bracketing node. - node_stack_.Push(parse_node); - return true; -} - -auto SemanticsParseTreeHandler::HandleVariableInitializer( - ParseTree::Node parse_node) -> bool { - // Temporarily remove name lookup entries added by the `var`. These will be - // restored by `VariableDeclaration`. - - // Save the storage ID. - auto it = name_lookup_.find( - node_stack_.PeekForNameId(ParseNodeKind::PatternBinding)); - CARBON_CHECK(it != name_lookup_.end()); - CARBON_CHECK(!it->second.empty()); - auto storage_id = it->second.back(); - - // Pop the name from lookup. - if (it->second.size() == 1) { - // Erase names that no longer resolve. - name_lookup_.erase(it); - } else { - it->second.pop_back(); - } - - node_stack_.Push(parse_node, storage_id); - - return true; -} - -auto SemanticsParseTreeHandler::HandleWhileCondition(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleWhileCondition"); - return false; -} - -auto SemanticsParseTreeHandler::HandleWhileConditionStart( - ParseTree::Node parse_node) -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleWhileConditionStart"); - return false; -} - -auto SemanticsParseTreeHandler::HandleWhileStatement(ParseTree::Node parse_node) - -> bool { - emitter_->Emit(parse_node, SemanticsTodo, "HandleWhileStatement"); - return false; -} - -} // namespace Carbon From ae393c515d11e7c2a0782538a6aed2a981c7a652 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 22:10:23 +0000 Subject: [PATCH 07/29] drafting --- toolchain/semantics/semantics_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/semantics/semantics_context.h b/toolchain/semantics/semantics_context.h index d755c7f7a9a86..5469aef95bb22 100644 --- a/toolchain/semantics/semantics_context.h +++ b/toolchain/semantics/semantics_context.h @@ -193,7 +193,7 @@ class SemanticsContext { } auto finished_params_stack() -> llvm::SmallVector< - std::pair> { + std::pair>& { return finished_params_stack_; } From 196f3192eb49bff0613f0f9aeb8e3b3e997d1735 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 22:20:36 +0000 Subject: [PATCH 08/29] x --- toolchain/semantics/BUILD | 2 +- toolchain/semantics/semantics_context.cpp | 83 +++++++++++ toolchain/semantics/semantics_context.h | 131 +++++------------- ...tics_handle_x.cpp => semantics_handle.cpp} | 129 +---------------- .../semantics_handle_call_expression.cpp | 68 +++++++++ .../semantics/semantics_handle_function.cpp | 77 ++++++++++ 6 files changed, 263 insertions(+), 227 deletions(-) rename toolchain/semantics/{semantics_handle_x.cpp => semantics_handle.cpp} (84%) create mode 100644 toolchain/semantics/semantics_handle_call_expression.cpp create mode 100644 toolchain/semantics/semantics_handle_function.cpp diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index 1d2caba58e592..56a43b1380e8a 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -70,7 +70,7 @@ cc_library( ] + # Glob handler files to avoid missing anyway. glob([ - "semantics_handle_*.cpp", + "semantics_handle*.cpp", ]), hdrs = [ "semantics_context.h", diff --git a/toolchain/semantics/semantics_context.cpp b/toolchain/semantics/semantics_context.cpp index 83f0438b1eb42..63a4fafb7b163 100644 --- a/toolchain/semantics/semantics_context.cpp +++ b/toolchain/semantics/semantics_context.cpp @@ -17,6 +17,42 @@ namespace Carbon { +SemanticsContext::SemanticsContext(const TokenizedBuffer& tokens, + DiagnosticEmitter& emitter, + const ParseTree& parse_tree, + SemanticsIR& semantics, + llvm::raw_ostream* vlog_stream) + : tokens_(&tokens), + emitter_(&emitter), + parse_tree_(&parse_tree), + semantics_(&semantics), + vlog_stream_(vlog_stream), + node_stack_(parse_tree, vlog_stream), + node_block_stack_("node_block_stack_", semantics.node_blocks(), + vlog_stream), + params_or_args_stack_("params_or_args_stack_", semantics.node_blocks(), + vlog_stream), + args_type_info_stack_("args_type_info_stack_", semantics.node_blocks(), + vlog_stream) {} + +auto SemanticsContext::TODO(ParseTree::Node parse_node, std::string label) + -> bool { + CARBON_DIAGNOSTIC(SemanticsTodo, Error, "Semantics TODO: {0}", std::string); + emitter_->Emit(parse_node, SemanticsTodo, std::move(label)); + return false; +} + +auto SemanticsContext::VerifyOnFinish() -> void { + // Information in all the various context objects should be cleaned up as + // various pieces of context go out of scope. At this point, nothing should + // remain. + // node_stack_ will still contain top-level entities. + CARBON_CHECK(name_lookup_.empty()) << name_lookup_.size(); + CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size(); + CARBON_CHECK(node_block_stack_.empty()) << node_block_stack_.size(); + CARBON_CHECK(params_or_args_stack_.empty()) << params_or_args_stack_.size(); +} + auto SemanticsContext::AddNode(SemanticsNode node) -> SemanticsNodeId { auto block = node_block_stack_.PeekForAdd(); CARBON_VLOG() << "AddNode " << block << ": " << node << "\n"; @@ -63,6 +99,45 @@ auto SemanticsContext::BindName(ParseTree::Node name_node, return name_id; } +auto SemanticsContext::TempRemoveLatestNameFromLookup() -> SemanticsNodeId { + // Save the storage ID. + auto it = name_lookup_.find( + node_stack_.PeekForNameId(ParseNodeKind::PatternBinding)); + CARBON_CHECK(it != name_lookup_.end()); + CARBON_CHECK(!it->second.empty()); + auto storage_id = it->second.back(); + + // Pop the name from lookup. + if (it->second.size() == 1) { + // Erase names that no longer resolve. + name_lookup_.erase(it); + } else { + it->second.pop_back(); + } + return storage_id; +} + +auto SemanticsContext::LookupName(ParseTree::Node parse_node, + llvm::StringRef name) -> SemanticsNodeId { + CARBON_DIAGNOSTIC(NameNotFound, Error, "Name {0} not found", llvm::StringRef); + + auto name_id = semantics_->GetStringID(name); + if (!name_id) { + emitter_->Emit(parse_node, NameNotFound, name); + return SemanticsNodeId::BuiltinInvalidType; + } + + auto it = name_lookup_.find(*name_id); + if (it == name_lookup_.end()) { + emitter_->Emit(parse_node, NameNotFound, name); + return SemanticsNodeId::BuiltinInvalidType; + } + CARBON_CHECK(!it->second.empty()) << "Should have been erased: " << name; + + // TODO: Check for ambiguous lookups. + return it->second.back(); +} + auto SemanticsContext::PushScope() -> void { scope_stack_.push_back({}); } auto SemanticsContext::PopScope() -> void { @@ -280,4 +355,12 @@ auto SemanticsContext::ParamOrArgSave(bool for_args) -> void { params_or_args.push_back(param_or_arg_id); } +auto SemanticsContext::PrintForStackDump(llvm::raw_ostream& output) const + -> void { + node_stack_.PrintForStackDump(output); + node_block_stack_.PrintForStackDump(output); + params_or_args_stack_.PrintForStackDump(output); + args_type_info_stack_.PrintForStackDump(output); +} + } // namespace Carbon diff --git a/toolchain/semantics/semantics_context.h b/toolchain/semantics/semantics_context.h index 5469aef95bb22..0957b011c11b0 100644 --- a/toolchain/semantics/semantics_context.h +++ b/toolchain/semantics/semantics_context.h @@ -23,44 +23,13 @@ class SemanticsContext { explicit SemanticsContext(const TokenizedBuffer& tokens, DiagnosticEmitter& emitter, const ParseTree& parse_tree, SemanticsIR& semantics, - llvm::raw_ostream* vlog_stream) - : tokens_(&tokens), - emitter_(&emitter), - parse_tree_(&parse_tree), - semantics_(&semantics), - vlog_stream_(vlog_stream), - node_stack_(parse_tree, vlog_stream), - node_block_stack_("node_block_stack_", semantics.node_blocks(), - vlog_stream), - params_or_args_stack_("params_or_args_stack_", semantics.node_blocks(), - vlog_stream), - args_type_info_stack_("args_type_info_stack_", semantics.node_blocks(), - vlog_stream) {} + llvm::raw_ostream* vlog_stream); // Marks an implementation TODO. Always returns false. - auto TODO(ParseTree::Node parse_node, std::string label) -> bool { - CARBON_DIAGNOSTIC(SemanticsTodo, Error, "Semantics TODO: {0}", std::string); - emitter_->Emit(parse_node, SemanticsTodo, std::move(label)); - return false; - } + auto TODO(ParseTree::Node parse_node, std::string label) -> bool; // Runs verification that the processing cleanly finished. - auto VerifyOnFinish() -> void { - // Information in all the various context objects should be cleaned up as - // various pieces of context go out of scope. At this point, nothing should - // remain. - // node_stack_ will still contain top-level entities. - CARBON_CHECK(name_lookup_.empty()) << name_lookup_.size(); - CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size(); - CARBON_CHECK(node_block_stack_.empty()) << node_block_stack_.size(); - CARBON_CHECK(params_or_args_stack_.empty()) << params_or_args_stack_.size(); - } - - // Pushes a new scope onto scope_stack_. - auto PushScope() -> void; - - // Pops the top scope from scope_stack_, cleaning up names from name_lookup_. - auto PopScope() -> void; + auto VerifyOnFinish() -> void; // Adds a node to the current block, returning the produced ID. auto AddNode(SemanticsNode node) -> SemanticsNodeId; @@ -69,6 +38,35 @@ class SemanticsContext { // result. auto AddNodeAndPush(ParseTree::Node parse_node, SemanticsNode node) -> void; + // Adds a name to name lookup. + auto AddNameToLookup(ParseTree::Node name_node, SemanticsStringId name_id, + SemanticsNodeId target_id) -> void; + + // Binds a DeclaredName to a target node with the given type. + auto BindName(ParseTree::Node name_node, SemanticsNodeId type_id, + SemanticsNodeId target_id) -> SemanticsStringId; + + // Temporarily remove name lookup entries added by the `var`. These will be + // restored by `VariableDeclaration` using `ReaddNameToLookup`. + auto TempRemoveLatestNameFromLookup() -> SemanticsNodeId; + + // Re-adds a name to name lookup. This is typically done through BindName, but + // can also be used to restore removed names. + auto ReaddNameToLookup(SemanticsStringId name_id, SemanticsNodeId storage_id) + -> void { + name_lookup_[name_id].push_back(storage_id); + } + + // Lookup up a name, returning the referenced node. + auto LookupName(ParseTree::Node parse_node, llvm::StringRef name) + -> SemanticsNodeId; + + // Pushes a new scope onto scope_stack_. + auto PushScope() -> void; + + // Pops the top scope from scope_stack_, cleaning up names from name_lookup_. + auto PopScope() -> void; + // Runs ImplicitAsImpl for a set of arguments and parameters. // // This will eventually need to support checking against multiple possible @@ -109,70 +107,7 @@ class SemanticsContext { auto ParamOrArgSave(bool for_args) -> void; // Prints information for a stack dump. - auto PrintForStackDump(llvm::raw_ostream& output) const -> void { - node_stack_.PrintForStackDump(output); - node_block_stack_.PrintForStackDump(output); - params_or_args_stack_.PrintForStackDump(output); - args_type_info_stack_.PrintForStackDump(output); - } - - // Adds a name to name lookup. - auto AddNameToLookup(ParseTree::Node name_node, SemanticsStringId name_id, - SemanticsNodeId target_id) -> void; - - // Temporarily remove name lookup entries added by the `var`. These will be - // restored by `VariableDeclaration` using `ReaddNameToLookup`. - auto TempRemoveLatestNameFromLookup() -> SemanticsNodeId { - // Save the storage ID. - auto it = name_lookup_.find( - node_stack_.PeekForNameId(ParseNodeKind::PatternBinding)); - CARBON_CHECK(it != name_lookup_.end()); - CARBON_CHECK(!it->second.empty()); - auto storage_id = it->second.back(); - - // Pop the name from lookup. - if (it->second.size() == 1) { - // Erase names that no longer resolve. - name_lookup_.erase(it); - } else { - it->second.pop_back(); - } - return storage_id; - } - - // Re-adds a name to name lookup. This is typically done through BindName, but - // can also be used to restore removed names. - auto ReaddNameToLookup(SemanticsStringId name_id, SemanticsNodeId storage_id) - -> void { - name_lookup_[name_id].push_back(storage_id); - } - - // Lookup up a name, returning the referenced node. - auto Lookup(ParseTree::Node parse_node, llvm::StringRef name) - -> SemanticsNodeId { - CARBON_DIAGNOSTIC(NameNotFound, Error, "Name {0} not found", - llvm::StringRef); - - auto name_id = semantics_->GetStringID(name); - if (!name_id) { - emitter_->Emit(parse_node, NameNotFound, name); - return SemanticsNodeId::BuiltinInvalidType; - } - - auto it = name_lookup_.find(*name_id); - if (it == name_lookup_.end()) { - emitter_->Emit(parse_node, NameNotFound, name); - return SemanticsNodeId::BuiltinInvalidType; - } - CARBON_CHECK(!it->second.empty()) << "Should have been erased: " << name; - - // TODO: Check for ambiguous lookups. - return it->second.back(); - } - - // Binds a DeclaredName to a target node with the given type. - auto BindName(ParseTree::Node name_node, SemanticsNodeId type_id, - SemanticsNodeId target_id) -> SemanticsStringId; + auto PrintForStackDump(llvm::raw_ostream& output) const -> void; auto tokens() -> const TokenizedBuffer& { return *tokens_; } diff --git a/toolchain/semantics/semantics_handle_x.cpp b/toolchain/semantics/semantics_handle.cpp similarity index 84% rename from toolchain/semantics/semantics_handle_x.cpp rename to toolchain/semantics/semantics_handle.cpp index 68eadf4118c57..632921ed35a4c 100644 --- a/toolchain/semantics/semantics_handle_x.cpp +++ b/toolchain/semantics/semantics_handle.cpp @@ -21,65 +21,6 @@ auto SemanticsHandleBreakStatementStart(SemanticsContext& context, return context.TODO(parse_node, "HandleBreakStatementStart"); } -auto SemanticsHandleCallExpression(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - auto [ir_id, refs_id] = context.ParamOrArgEnd( - /*for_args=*/true, ParseNodeKind::CallExpressionStart); - - // TODO: Convert to call expression. - auto [call_expr_parse_node, name_id] = - context.node_stack().PopForParseNodeAndNodeId( - ParseNodeKind::CallExpressionStart); - auto name_node = context.semantics().GetNode(name_id); - if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) { - // TODO: Work on error. - context.TODO(parse_node, "Not a callable name"); - context.node_stack().Push(parse_node, name_id); - return true; - } - - auto [_, callable_id] = name_node.GetAsFunctionDeclaration(); - auto callable = context.semantics().GetCallable(callable_id); - - CARBON_DIAGNOSTIC(NoMatchingCall, Error, "No matching callable was found."); - auto diagnostic = - context.emitter().Build(call_expr_parse_node, NoMatchingCall); - if (!context.ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), - callable.param_refs_id, &diagnostic)) { - diagnostic.Emit(); - context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinInvalidType); - return true; - } - - CARBON_CHECK(context.ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), - callable.param_refs_id, - /*diagnostic=*/nullptr)); - - auto call_id = context.semantics().AddCall({ir_id, refs_id}); - // TODO: Propagate return types from callable. - auto call_node_id = context.AddNode(SemanticsNode::Call::Make( - call_expr_parse_node, callable.return_type_id, call_id, callable_id)); - - context.node_stack().Push(parse_node, call_node_id); - return true; -} - -auto SemanticsHandleCallExpressionComma(SemanticsContext& context, - ParseTree::Node /*parse_node*/) - -> bool { - context.ParamOrArgComma(/*for_args=*/true); - return true; -} - -auto SemanticsHandleCallExpressionStart(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - auto name_id = - context.node_stack().PopForNodeId(ParseNodeKind::NameReference); - context.node_stack().Push(parse_node, name_id); - context.ParamOrArgStart(); - return true; -} - auto SemanticsHandleClassDeclaration(SemanticsContext& context, ParseTree::Node parse_node) -> bool { return context.TODO(parse_node, "HandleClassDeclaration"); @@ -238,74 +179,6 @@ auto SemanticsHandleForStatement(SemanticsContext& context, return context.TODO(parse_node, "HandleForStatement"); } -auto SemanticsHandleFunctionDeclaration(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleFunctionDeclaration"); -} - -auto SemanticsHandleFunctionDefinition(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - // Merges code block children up under the FunctionDefinitionStart. - while (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) != - ParseNodeKind::FunctionDefinitionStart) { - context.node_stack().PopAndIgnore(); - } - auto decl_id = - context.node_stack().PopForNodeId(ParseNodeKind::FunctionDefinitionStart); - - context.return_scope_stack().pop_back(); - context.PopScope(); - auto block_id = context.node_block_stack().Pop(); - context.AddNode( - SemanticsNode::FunctionDefinition::Make(parse_node, decl_id, block_id)); - context.node_stack().Push(parse_node); - - return true; -} - -auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context, - ParseTree::Node parse_node) - -> bool { - SemanticsNodeId return_type_id = SemanticsNodeId::Invalid; - if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == - ParseNodeKind::ReturnType) { - return_type_id = - context.node_stack().PopForNodeId(ParseNodeKind::ReturnType); - } - context.node_stack().PopForSoloParseNode(ParseNodeKind::ParameterList); - auto [param_ir_id, param_refs_id] = - context.finished_params_stack().pop_back_val(); - auto name_node = - context.node_stack().PopForSoloParseNode(ParseNodeKind::DeclaredName); - auto fn_node = context.node_stack().PopForSoloParseNode( - ParseNodeKind::FunctionIntroducer); - - auto name_str = context.parse_tree().GetNodeText(name_node); - auto name_id = context.semantics().AddString(name_str); - - auto callable_id = - context.semantics().AddCallable({.param_ir_id = param_ir_id, - .param_refs_id = param_refs_id, - .return_type_id = return_type_id}); - auto decl_id = context.AddNode( - SemanticsNode::FunctionDeclaration::Make(fn_node, name_id, callable_id)); - context.AddNameToLookup(name_node, name_id, decl_id); - - context.node_block_stack().Push(); - context.PushScope(); - context.return_scope_stack().push_back(decl_id); - context.node_stack().Push(parse_node, decl_id); - - return true; -} - -auto SemanticsHandleFunctionIntroducer(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - // No action, just a bracketing node. - context.node_stack().Push(parse_node); - return true; -} - auto SemanticsHandleGenericPatternBinding(SemanticsContext& context, ParseTree::Node parse_node) -> bool { return context.TODO(parse_node, "GenericPatternBinding"); @@ -445,7 +318,7 @@ auto SemanticsHandleLiteral(SemanticsContext& context, auto SemanticsHandleNameReference(SemanticsContext& context, ParseTree::Node parse_node) -> bool { auto name = context.parse_tree().GetNodeText(parse_node); - context.node_stack().Push(parse_node, context.Lookup(parse_node, name)); + context.node_stack().Push(parse_node, context.LookupName(parse_node, name)); return true; } diff --git a/toolchain/semantics/semantics_handle_call_expression.cpp b/toolchain/semantics/semantics_handle_call_expression.cpp new file mode 100644 index 0000000000000..a3646622e2202 --- /dev/null +++ b/toolchain/semantics/semantics_handle_call_expression.cpp @@ -0,0 +1,68 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandleCallExpression(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/true, ParseNodeKind::CallExpressionStart); + + // TODO: Convert to call expression. + auto [call_expr_parse_node, name_id] = + context.node_stack().PopForParseNodeAndNodeId( + ParseNodeKind::CallExpressionStart); + auto name_node = context.semantics().GetNode(name_id); + if (name_node.kind() != SemanticsNodeKind::FunctionDeclaration) { + // TODO: Work on error. + context.TODO(parse_node, "Not a callable name"); + context.node_stack().Push(parse_node, name_id); + return true; + } + + auto [_, callable_id] = name_node.GetAsFunctionDeclaration(); + auto callable = context.semantics().GetCallable(callable_id); + + CARBON_DIAGNOSTIC(NoMatchingCall, Error, "No matching callable was found."); + auto diagnostic = + context.emitter().Build(call_expr_parse_node, NoMatchingCall); + if (!context.ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), + callable.param_refs_id, &diagnostic)) { + diagnostic.Emit(); + context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinInvalidType); + return true; + } + + CARBON_CHECK(context.ImplicitAsForArgs(ir_id, refs_id, name_node.parse_node(), + callable.param_refs_id, + /*diagnostic=*/nullptr)); + + auto call_id = context.semantics().AddCall({ir_id, refs_id}); + // TODO: Propagate return types from callable. + auto call_node_id = context.AddNode(SemanticsNode::Call::Make( + call_expr_parse_node, callable.return_type_id, call_id, callable_id)); + + context.node_stack().Push(parse_node, call_node_id); + return true; +} + +auto SemanticsHandleCallExpressionComma(SemanticsContext& context, + ParseTree::Node /*parse_node*/) + -> bool { + context.ParamOrArgComma(/*for_args=*/true); + return true; +} + +auto SemanticsHandleCallExpressionStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto name_id = + context.node_stack().PopForNodeId(ParseNodeKind::NameReference); + context.node_stack().Push(parse_node, name_id); + context.ParamOrArgStart(); + return true; +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_handle_function.cpp b/toolchain/semantics/semantics_handle_function.cpp new file mode 100644 index 0000000000000..53899d03f667f --- /dev/null +++ b/toolchain/semantics/semantics_handle_function.cpp @@ -0,0 +1,77 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandleFunctionDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleFunctionDeclaration"); +} + +auto SemanticsHandleFunctionDefinition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // Merges code block children up under the FunctionDefinitionStart. + while (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) != + ParseNodeKind::FunctionDefinitionStart) { + context.node_stack().PopAndIgnore(); + } + auto decl_id = + context.node_stack().PopForNodeId(ParseNodeKind::FunctionDefinitionStart); + + context.return_scope_stack().pop_back(); + context.PopScope(); + auto block_id = context.node_block_stack().Pop(); + context.AddNode( + SemanticsNode::FunctionDefinition::Make(parse_node, decl_id, block_id)); + context.node_stack().Push(parse_node); + + return true; +} + +auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + SemanticsNodeId return_type_id = SemanticsNodeId::Invalid; + if (context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == + ParseNodeKind::ReturnType) { + return_type_id = + context.node_stack().PopForNodeId(ParseNodeKind::ReturnType); + } + context.node_stack().PopForSoloParseNode(ParseNodeKind::ParameterList); + auto [param_ir_id, param_refs_id] = + context.finished_params_stack().pop_back_val(); + auto name_node = + context.node_stack().PopForSoloParseNode(ParseNodeKind::DeclaredName); + auto fn_node = context.node_stack().PopForSoloParseNode( + ParseNodeKind::FunctionIntroducer); + + auto name_str = context.parse_tree().GetNodeText(name_node); + auto name_id = context.semantics().AddString(name_str); + + auto callable_id = + context.semantics().AddCallable({.param_ir_id = param_ir_id, + .param_refs_id = param_refs_id, + .return_type_id = return_type_id}); + auto decl_id = context.AddNode( + SemanticsNode::FunctionDeclaration::Make(fn_node, name_id, callable_id)); + context.AddNameToLookup(name_node, name_id, decl_id); + + context.node_block_stack().Push(); + context.PushScope(); + context.return_scope_stack().push_back(decl_id); + context.node_stack().Push(parse_node, decl_id); + + return true; +} + +auto SemanticsHandleFunctionIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + // No action, just a bracketing node. + context.node_stack().Push(parse_node); + return true; +} + +} // namespace Carbon From f6817414447cb8cec718d3bed3c299e0aafa3ecf Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 22:40:04 +0000 Subject: [PATCH 09/29] x --- toolchain/common/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/common/BUILD b/toolchain/common/BUILD index ddb7036cd2086..d5f43c698c83e 100644 --- a/toolchain/common/BUILD +++ b/toolchain/common/BUILD @@ -2,7 +2,7 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -package(default_visibility = ["//toolchain:__subpackages__"]) +package(default_visibility = ["//visibility:public"]) cc_library( name = "index_base", From d4d1d6d57eb19ba94431dee371e87a27f88c45b0 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Mon, 8 May 2023 23:30:26 +0000 Subject: [PATCH 10/29] Refactoring lowering logic into separate files. --- toolchain/lowering/BUILD | 11 +- toolchain/lowering/lower_to_llvm.cpp | 6 +- toolchain/lowering/lowering.cpp | 209 ------------------ toolchain/lowering/lowering_context.cpp | 65 ++++++ .../{lowering.h => lowering_context.h} | 44 ++-- toolchain/lowering/lowering_handle.cpp | 176 +++++++++++++++ 6 files changed, 280 insertions(+), 231 deletions(-) delete mode 100644 toolchain/lowering/lowering.cpp create mode 100644 toolchain/lowering/lowering_context.cpp rename toolchain/lowering/{lowering.h => lowering_context.h} (62%) create mode 100644 toolchain/lowering/lowering_handle.cpp diff --git a/toolchain/lowering/BUILD b/toolchain/lowering/BUILD index feb011966ad65..aa19a8f3f129f 100644 --- a/toolchain/lowering/BUILD +++ b/toolchain/lowering/BUILD @@ -9,7 +9,7 @@ cc_library( srcs = ["lower_to_llvm.cpp"], hdrs = ["lower_to_llvm.h"], deps = [ - ":lowering", + ":lowering_context", "//toolchain/semantics:semantics_ir", "@llvm-project//llvm:Core", "@llvm-project//llvm:Support", @@ -17,9 +17,12 @@ cc_library( ) cc_library( - name = "lowering", - srcs = ["lowering.cpp"], - hdrs = ["lowering.h"], + name = "lowering_context", + srcs = [ + "lowering_context.cpp", + "lowering_handle.cpp", + ], + hdrs = ["lowering_context.h"], deps = [ "//common:check", "//toolchain/semantics:semantics_ir", diff --git a/toolchain/lowering/lower_to_llvm.cpp b/toolchain/lowering/lower_to_llvm.cpp index f2bae57b9e4e1..35c695a162af1 100644 --- a/toolchain/lowering/lower_to_llvm.cpp +++ b/toolchain/lowering/lower_to_llvm.cpp @@ -4,15 +4,15 @@ #include "toolchain/lowering/lower_to_llvm.h" -#include "toolchain/lowering/lowering.h" +#include "toolchain/lowering/lowering_context.h" namespace Carbon { auto LowerToLLVM(llvm::LLVMContext& llvm_context, llvm::StringRef module_name, const SemanticsIR& semantics_ir) -> std::unique_ptr { - Lowering lowering(llvm_context, module_name, semantics_ir); - return lowering.Run(); + LoweringContext context(llvm_context, module_name, semantics_ir); + return context.Run(); } } // namespace Carbon diff --git a/toolchain/lowering/lowering.cpp b/toolchain/lowering/lowering.cpp deleted file mode 100644 index a17c8930e3825..0000000000000 --- a/toolchain/lowering/lowering.cpp +++ /dev/null @@ -1,209 +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 "toolchain/lowering/lowering.h" - -#include "toolchain/semantics/semantics_ir.h" - -namespace Carbon { - -Lowering::Lowering(llvm::LLVMContext& llvm_context, llvm::StringRef module_name, - const SemanticsIR& semantics_ir) - : llvm_context_(&llvm_context), - llvm_module_(std::make_unique(module_name, llvm_context)), - builder_(llvm_context), - semantics_ir_(&semantics_ir), - lowered_nodes_(semantics_ir_->nodes_size(), nullptr) { - CARBON_CHECK(!semantics_ir.has_errors()) - << "Generating LLVM IR from invalid SemanticsIR is unsupported."; -} - -auto Lowering::Run() -> std::unique_ptr { - CARBON_CHECK(llvm_module_) << "Run can only be called once."; - - LowerBlock(semantics_ir_->top_node_block_id()); - - while (!todo_blocks_.empty()) { - auto [llvm_block, block_id] = todo_blocks_.pop_back_val(); - builder_.SetInsertPoint(llvm_block); - LowerBlock(block_id); - } - - return std::move(llvm_module_); -} - -auto Lowering::LowerBlock(SemanticsNodeBlockId block_id) -> void { - for (const auto& node_id : semantics_ir_->GetNodeBlock(block_id)) { - auto node = semantics_ir_->GetNode(node_id); - switch (node.kind()) { -#define CARBON_SEMANTICS_NODE_KIND(Name) \ - case SemanticsNodeKind::Name: \ - Handle##Name##Node(node_id, node); \ - break; -#include "toolchain/semantics/semantics_node_kind.def" - } - } -} - -auto Lowering::LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type* { - CARBON_CHECK(node_id.is_valid()); - switch (node_id.index) { - case SemanticsBuiltinKind::EmptyTuple.AsInt(): - // TODO: Should probably switch this to an actual empty tuple in the - // future, but it's implemented as void for now. - return builder_.getVoidTy(); - case SemanticsBuiltinKind::IntegerType.AsInt(): - // TODO: Handle different sizes. - return builder_.getInt32Ty(); - default: - CARBON_FATAL() << "Cannot use node as type: " << node_id; - } -} - -auto Lowering::HandleInvalidNode(SemanticsNodeId /*node_id*/, - SemanticsNode /*node*/) -> void { - llvm_unreachable("never in actual IR"); -} - -auto Lowering::HandleCrossReferenceNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleAssignNode(SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleBinaryOperatorAddNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleBindNameNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleBuiltinNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleCallNode(SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleCodeBlockNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleFunctionDeclarationNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - auto [name_id, callable_id] = node.GetAsFunctionDeclaration(); - auto callable = semantics_ir_->GetCallable(callable_id); - - // TODO: Lower type information for the arguments prior to building args. - auto param_refs = semantics_ir_->GetNodeBlock(callable.param_refs_id); - llvm::SmallVector args; - args.resize_for_overwrite(param_refs.size()); - for (int i = 0; i < static_cast(param_refs.size()); ++i) { - args[i] = LowerNodeToType(semantics_ir_->GetNode(param_refs[i]).type_id()); - } - - llvm::Type* return_type = LowerNodeToType( - callable.return_type_id.is_valid() ? callable.return_type_id - : SemanticsNodeId::BuiltinEmptyTuple); - llvm::FunctionType* function_type = - llvm::FunctionType::get(return_type, args, /*isVarArg=*/false); - auto* function = llvm::Function::Create( - function_type, llvm::Function::ExternalLinkage, - semantics_ir_->GetString(name_id), llvm_module_.get()); - - // Set parameter names. - for (int i = 0; i < static_cast(param_refs.size()); ++i) { - auto [param_name_id, _] = - semantics_ir_->GetNode(param_refs[i]).GetAsBindName(); - function->getArg(i)->setName(semantics_ir_->GetString(param_name_id)); - } -} - -auto Lowering::HandleFunctionDefinitionNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - auto [declaration_id, body_block_id] = node.GetAsFunctionDefinition(); - auto [name_id, callable_id] = - semantics_ir_->GetNode(declaration_id).GetAsFunctionDeclaration(); - - llvm::Function* function = - llvm_module_->getFunction(semantics_ir_->GetString(name_id)); - - // Create a new basic block to start insertion into. - llvm::BasicBlock* body = - llvm::BasicBlock::Create(*llvm_context_, "entry", function); - todo_blocks_.push_back({body, body_block_id}); -} - -auto Lowering::HandleIntegerLiteralNode(SemanticsNodeId node_id, - SemanticsNode node) -> void { - SemanticsIntegerLiteralId int_id = node.GetAsIntegerLiteral(); - llvm::APInt i = semantics_ir_->GetIntegerLiteral(int_id); - llvm::Value* v = - llvm::ConstantInt::get(builder_.getInt32Ty(), i.getLimitedValue()); - lowered_nodes_[node_id.index] = v; -} - -auto Lowering::HandleRealLiteralNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleReturnNode(SemanticsNodeId /*node_id*/, - SemanticsNode /*node*/) -> void { - builder_.CreateRetVoid(); -} - -auto Lowering::HandleReturnExpressionNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - SemanticsNodeId expr_id = node.GetAsReturnExpression(); - builder_.CreateRet(lowered_nodes_[expr_id.index]); -} - -auto Lowering::HandleStringLiteralNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructMemberAccessNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructTypeNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructTypeFieldNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructValueNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStubReferenceNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleVarStorageNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -} // namespace Carbon diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp new file mode 100644 index 0000000000000..9cf3764225f39 --- /dev/null +++ b/toolchain/lowering/lowering_context.cpp @@ -0,0 +1,65 @@ +// 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 "toolchain/lowering/lowering_context.h" + +#include "toolchain/semantics/semantics_ir.h" + +namespace Carbon { + +LoweringContext::LoweringContext(llvm::LLVMContext& llvm_context, + llvm::StringRef module_name, + const SemanticsIR& semantics_ir) + : llvm_context_(&llvm_context), + llvm_module_(std::make_unique(module_name, llvm_context)), + builder_(llvm_context), + semantics_ir_(&semantics_ir), + lowered_nodes_(semantics_ir_->nodes_size(), nullptr) { + CARBON_CHECK(!semantics_ir.has_errors()) + << "Generating LLVM IR from invalid SemanticsIR is unsupported."; +} + +auto LoweringContext::Run() -> std::unique_ptr { + CARBON_CHECK(llvm_module_) << "Run can only be called once."; + + LowerBlock(semantics_ir_->top_node_block_id()); + + while (!todo_blocks_.empty()) { + auto [llvm_block, block_id] = todo_blocks_.pop_back_val(); + builder_.SetInsertPoint(llvm_block); + LowerBlock(block_id); + } + + return std::move(llvm_module_); +} + +auto LoweringContext::LowerBlock(SemanticsNodeBlockId block_id) -> void { + for (const auto& node_id : semantics_ir_->GetNodeBlock(block_id)) { + auto node = semantics_ir_->GetNode(node_id); + switch (node.kind()) { +#define CARBON_SEMANTICS_NODE_KIND(Name) \ + case SemanticsNodeKind::Name: \ + LoweringHandle##Name(*this, node_id, node); \ + break; +#include "toolchain/semantics/semantics_node_kind.def" + } + } +} + +auto LoweringContext::LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type* { + CARBON_CHECK(node_id.is_valid()); + switch (node_id.index) { + case SemanticsBuiltinKind::EmptyTuple.AsInt(): + // TODO: Should probably switch this to an actual empty tuple in the + // future, but it's implemented as void for now. + return builder_.getVoidTy(); + case SemanticsBuiltinKind::IntegerType.AsInt(): + // TODO: Handle different sizes. + return builder_.getInt32Ty(); + default: + CARBON_FATAL() << "Cannot use node as type: " << node_id; + } +} + +} // namespace Carbon diff --git a/toolchain/lowering/lowering.h b/toolchain/lowering/lowering_context.h similarity index 62% rename from toolchain/lowering/lowering.h rename to toolchain/lowering/lowering_context.h index 0c323f1b5f6bd..2b2f2cfe811f5 100644 --- a/toolchain/lowering/lowering.h +++ b/toolchain/lowering/lowering_context.h @@ -2,8 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_H_ -#define CARBON_TOOLCHAIN_LOWERING_LOWERING_H_ +#ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_ +#define CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" @@ -17,27 +17,34 @@ namespace Carbon { // // This carries state for lowering. `Run()` should only be called once, and // handles the main execution. -class Lowering { +class LoweringContext { public: - explicit Lowering(llvm::LLVMContext& llvm_context, - llvm::StringRef module_name, - const SemanticsIR& semantics_ir); + explicit LoweringContext(llvm::LLVMContext& llvm_context, + llvm::StringRef module_name, + const SemanticsIR& semantics_ir); // Lowers the SemanticsIR to LLVM IR. auto Run() -> std::unique_ptr; - private: - // Declare handlers for each SemanticsIR node. -#define CARBON_SEMANTICS_NODE_KIND(Name) \ - auto Handle##Name##Node(SemanticsNodeId node_id, SemanticsNode node)->void; -#include "toolchain/semantics/semantics_node_kind.def" + // Returns a type for the given node. + auto LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type*; + + auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; } + auto llvm_module() -> llvm::Module& { return *llvm_module_; } + auto builder() -> llvm::IRBuilder<>& { return builder_; } + auto semantics_ir() -> const SemanticsIR& { return *semantics_ir_; } + auto todo_blocks() -> llvm::SmallVector< + std::pair>& { + return todo_blocks_; + } + auto lowered_nodes() -> llvm::SmallVector& { + return lowered_nodes_; + } + private: // Runs lowering for a block. auto LowerBlock(SemanticsNodeBlockId block_id) -> void; - // Returns a type for the given node. - auto LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type*; - // State for building the LLVM IR. llvm::LLVMContext* llvm_context_; std::unique_ptr llvm_module_; @@ -61,6 +68,13 @@ class Lowering { llvm::SmallVector lowered_nodes_; }; +// Declare handlers for each SemanticsIR node. +#define CARBON_SEMANTICS_NODE_KIND(Name) \ + auto LoweringHandle##Name(LoweringContext& context, SemanticsNodeId node_id, \ + SemanticsNode node) \ + ->void; +#include "toolchain/semantics/semantics_node_kind.def" + } // namespace Carbon -#endif // CARBON_TOOLCHAIN_LOWERING_LOWERING_H_ +#endif // CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_ diff --git a/toolchain/lowering/lowering_handle.cpp b/toolchain/lowering/lowering_handle.cpp new file mode 100644 index 0000000000000..ff1626e0e9a65 --- /dev/null +++ b/toolchain/lowering/lowering_handle.cpp @@ -0,0 +1,176 @@ +// 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 "toolchain/lowering/lowering_context.h" + +namespace Carbon { + +auto LoweringHandleInvalid(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode /*node*/) + -> void { + llvm_unreachable("never in actual IR"); +} + +auto LoweringHandleCrossReference(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleAssign(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleBinaryOperatorAdd(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleBindName(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleBuiltin(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleCall(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleCodeBlock(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleFunctionDeclaration(LoweringContext& context, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + auto [name_id, callable_id] = node.GetAsFunctionDeclaration(); + auto callable = context.semantics_ir().GetCallable(callable_id); + + // TODO: Lower type information for the arguments prior to building args. + auto param_refs = context.semantics_ir().GetNodeBlock(callable.param_refs_id); + llvm::SmallVector args; + args.resize_for_overwrite(param_refs.size()); + for (int i = 0; i < static_cast(param_refs.size()); ++i) { + args[i] = context.LowerNodeToType( + context.semantics_ir().GetNode(param_refs[i]).type_id()); + } + + llvm::Type* return_type = context.LowerNodeToType( + callable.return_type_id.is_valid() ? callable.return_type_id + : SemanticsNodeId::BuiltinEmptyTuple); + llvm::FunctionType* function_type = + llvm::FunctionType::get(return_type, args, /*isVarArg=*/false); + auto* function = llvm::Function::Create( + function_type, llvm::Function::ExternalLinkage, + context.semantics_ir().GetString(name_id), context.llvm_module()); + + // Set parameter names. + for (int i = 0; i < static_cast(param_refs.size()); ++i) { + auto [param_name_id, _] = + context.semantics_ir().GetNode(param_refs[i]).GetAsBindName(); + function->getArg(i)->setName( + context.semantics_ir().GetString(param_name_id)); + } +} + +auto LoweringHandleFunctionDefinition(LoweringContext& context, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + auto [declaration_id, body_block_id] = node.GetAsFunctionDefinition(); + auto [name_id, callable_id] = + context.semantics_ir().GetNode(declaration_id).GetAsFunctionDeclaration(); + + llvm::Function* function = context.llvm_module().getFunction( + context.semantics_ir().GetString(name_id)); + + // Create a new basic block to start insertion into. + llvm::BasicBlock* body = + llvm::BasicBlock::Create(context.llvm_context(), "entry", function); + context.todo_blocks().push_back({body, body_block_id}); +} + +auto LoweringHandleIntegerLiteral(LoweringContext& context, + SemanticsNodeId node_id, SemanticsNode node) + -> void { + SemanticsIntegerLiteralId int_id = node.GetAsIntegerLiteral(); + llvm::APInt i = context.semantics_ir().GetIntegerLiteral(int_id); + llvm::Value* v = llvm::ConstantInt::get(context.builder().getInt32Ty(), + i.getLimitedValue()); + context.lowered_nodes()[node_id.index] = v; +} + +auto LoweringHandleRealLiteral(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleReturn(LoweringContext& context, SemanticsNodeId /*node_id*/, + SemanticsNode /*node*/) -> void { + context.builder().CreateRetVoid(); +} + +auto LoweringHandleReturnExpression(LoweringContext& context, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + SemanticsNodeId expr_id = node.GetAsReturnExpression(); + context.builder().CreateRet(context.lowered_nodes()[expr_id.index]); +} + +auto LoweringHandleStringLiteral(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructMemberAccess(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructType(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructTypeField(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructValue(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStubReference(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleVarStorage(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +} // namespace Carbon From 3b6c75145ae12132000fbada2619b03186c25659 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 17:49:28 +0000 Subject: [PATCH 11/29] x --- toolchain/semantics/semantics_handle.cpp | 185 ------------------ .../semantics/semantics_handle_class.cpp | 29 +++ .../semantics/semantics_handle_interface.cpp | 30 +++ .../semantics/semantics_handle_package.cpp | 34 ++++ .../semantics/semantics_handle_struct.cpp | 128 ++++++++++++ 5 files changed, 221 insertions(+), 185 deletions(-) create mode 100644 toolchain/semantics/semantics_handle_class.cpp create mode 100644 toolchain/semantics/semantics_handle_interface.cpp create mode 100644 toolchain/semantics/semantics_handle_package.cpp create mode 100644 toolchain/semantics/semantics_handle_struct.cpp diff --git a/toolchain/semantics/semantics_handle.cpp b/toolchain/semantics/semantics_handle.cpp index 632921ed35a4c..7699b37fcd628 100644 --- a/toolchain/semantics/semantics_handle.cpp +++ b/toolchain/semantics/semantics_handle.cpp @@ -21,26 +21,6 @@ auto SemanticsHandleBreakStatementStart(SemanticsContext& context, return context.TODO(parse_node, "HandleBreakStatementStart"); } -auto SemanticsHandleClassDeclaration(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleClassDeclaration"); -} - -auto SemanticsHandleClassDefinition(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleClassDefinition"); -} - -auto SemanticsHandleClassDefinitionStart(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleClassDefinitionStart"); -} - -auto SemanticsHandleClassIntroducer(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleClassIntroducer"); -} - auto SemanticsHandleCodeBlock(SemanticsContext& context, ParseTree::Node parse_node) -> bool { return context.TODO(parse_node, "HandleCodeBlock"); @@ -231,27 +211,6 @@ auto SemanticsHandleInfixOperator(SemanticsContext& context, return true; } -auto SemanticsHandleInterfaceDeclaration(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleInterfaceDeclaration"); -} - -auto SemanticsHandleInterfaceDefinition(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleInterfaceDefinition"); -} - -auto SemanticsHandleInterfaceDefinitionStart(SemanticsContext& context, - ParseTree::Node parse_node) - -> bool { - return context.TODO(parse_node, "HandleInterfaceDefinitionStart"); -} - -auto SemanticsHandleInterfaceIntroducer(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleInterfaceIntroducer"); -} - auto SemanticsHandleInvalidParse(SemanticsContext& context, ParseTree::Node parse_node) -> bool { return context.TODO(parse_node, "HandleInvalidParse"); @@ -346,31 +305,6 @@ auto SemanticsHandleNamedConstraintIntroducer(SemanticsContext& context, return context.TODO(parse_node, "HandleNamedConstraintIntroducer"); } -auto SemanticsHandlePackageApi(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandlePackageApi"); -} - -auto SemanticsHandlePackageDirective(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandlePackageDirective"); -} - -auto SemanticsHandlePackageImpl(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandlePackageImpl"); -} - -auto SemanticsHandlePackageIntroducer(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandlePackageIntroducer"); -} - -auto SemanticsHandlePackageLibrary(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandlePackageLibrary"); -} - auto SemanticsHandleParameterList(SemanticsContext& context, ParseTree::Node parse_node) -> bool { auto [ir_id, refs_id] = context.ParamOrArgEnd( @@ -523,125 +457,6 @@ auto SemanticsHandleSelfValueIdentifier(SemanticsContext& context, return context.TODO(parse_node, "HandleSelfValueIdentifier"); } -auto SemanticsHandleStructComma(SemanticsContext& context, - ParseTree::Node /*parse_node*/) -> bool { - context.ParamOrArgComma( - /*for_args=*/context.parse_tree().node_kind( - context.node_stack().PeekParseNode()) != - ParseNodeKind::StructFieldType); - return true; -} - -auto SemanticsHandleStructFieldDesignator(SemanticsContext& context, - ParseTree::Node /*parse_node*/) - -> bool { - // This leaves the designated name on top because the `.` isn't interesting. - CARBON_CHECK( - context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == - ParseNodeKind::DesignatedName); - return true; -} - -auto SemanticsHandleStructFieldType(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - auto [type_node, type_id] = context.node_stack().PopForParseNodeAndNodeId(); - SemanticsNodeId cast_type_id = context.ImplicitAsRequired( - type_node, type_id, SemanticsNodeId::BuiltinTypeType); - - auto [name_node, name_id] = context.node_stack().PopForParseNodeAndNameId( - ParseNodeKind::DesignatedName); - - context.AddNode( - SemanticsNode::StructTypeField::Make(name_node, cast_type_id, name_id)); - context.node_stack().Push(parse_node); - return true; -} - -auto SemanticsHandleStructFieldUnknown(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - return context.TODO(parse_node, "HandleStructFieldUnknown"); -} - -auto SemanticsHandleStructFieldValue(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - auto [value_parse_node, value_node_id] = - context.node_stack().PopForParseNodeAndNodeId(); - auto [_, name_id] = context.node_stack().PopForParseNodeAndNameId( - ParseNodeKind::DesignatedName); - - // Store the name for the type. - auto type_block_id = context.args_type_info_stack().PeekForAdd(); - context.semantics().AddNode( - type_block_id, - SemanticsNode::StructTypeField::Make( - parse_node, context.semantics().GetNode(value_node_id).type_id(), - name_id)); - - // Push the value back on the stack as an argument. - context.node_stack().Push(parse_node, value_node_id); - return true; -} - -auto SemanticsHandleStructLiteral(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - auto [ir_id, refs_id] = context.ParamOrArgEnd( - /*for_args=*/true, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - - context.PopScope(); - context.node_stack().PopAndDiscardSoloParseNode( - ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - auto type_block_id = context.args_type_info_stack().Pop(); - - // Special-case `{}`. - if (refs_id == SemanticsNodeBlockId::Empty) { - context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinEmptyStruct); - return true; - } - - // Construct a type for the literal. Each field is one node, so ir_id and - // refs_id match. - auto refs = context.semantics().GetNodeBlock(refs_id); - auto type_id = context.AddNode(SemanticsNode::StructType::Make( - parse_node, type_block_id, type_block_id)); - - auto value_id = context.AddNode( - SemanticsNode::StructValue::Make(parse_node, type_id, ir_id, refs_id)); - context.node_stack().Push(parse_node, value_id); - return true; -} - -auto SemanticsHandleStructLiteralOrStructTypeLiteralStart( - SemanticsContext& context, ParseTree::Node parse_node) -> bool { - context.PushScope(); - context.node_stack().Push(parse_node); - // At this point we aren't sure whether this will be a value or type literal, - // so we push onto args irrespective. It just won't be used for a type - // literal. - context.args_type_info_stack().Push(); - context.ParamOrArgStart(); - return true; -} - -auto SemanticsHandleStructTypeLiteral(SemanticsContext& context, - ParseTree::Node parse_node) -> bool { - auto [ir_id, refs_id] = context.ParamOrArgEnd( - /*for_args=*/false, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - - context.PopScope(); - context.node_stack().PopAndDiscardSoloParseNode( - ParseNodeKind::StructLiteralOrStructTypeLiteralStart); - // This is only used for value literals. - context.args_type_info_stack().Pop(); - - CARBON_CHECK(refs_id != SemanticsNodeBlockId::Empty) - << "{} is handled by StructLiteral."; - - auto type_id = context.AddNode( - SemanticsNode::StructType::Make(parse_node, ir_id, refs_id)); - context.node_stack().Push(parse_node, type_id); - return true; -} - auto SemanticsHandleTemplate(SemanticsContext& context, ParseTree::Node parse_node) -> bool { return context.TODO(parse_node, "HandleTemplate"); diff --git a/toolchain/semantics/semantics_handle_class.cpp b/toolchain/semantics/semantics_handle_class.cpp new file mode 100644 index 0000000000000..7b422f2fbdbd1 --- /dev/null +++ b/toolchain/semantics/semantics_handle_class.cpp @@ -0,0 +1,29 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandleClassDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassDeclaration"); +} + +auto SemanticsHandleClassDefinition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassDefinition"); +} + +auto SemanticsHandleClassDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassDefinitionStart"); +} + +auto SemanticsHandleClassIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleClassIntroducer"); +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_handle_interface.cpp b/toolchain/semantics/semantics_handle_interface.cpp new file mode 100644 index 0000000000000..bca7b51a746be --- /dev/null +++ b/toolchain/semantics/semantics_handle_interface.cpp @@ -0,0 +1,30 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandleInterfaceDeclaration(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInterfaceDeclaration"); +} + +auto SemanticsHandleInterfaceDefinition(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInterfaceDefinition"); +} + +auto SemanticsHandleInterfaceDefinitionStart(SemanticsContext& context, + ParseTree::Node parse_node) + -> bool { + return context.TODO(parse_node, "HandleInterfaceDefinitionStart"); +} + +auto SemanticsHandleInterfaceIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleInterfaceIntroducer"); +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_handle_package.cpp b/toolchain/semantics/semantics_handle_package.cpp new file mode 100644 index 0000000000000..285d925658021 --- /dev/null +++ b/toolchain/semantics/semantics_handle_package.cpp @@ -0,0 +1,34 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandlePackageApi(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageApi"); +} + +auto SemanticsHandlePackageDirective(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageDirective"); +} + +auto SemanticsHandlePackageImpl(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageImpl"); +} + +auto SemanticsHandlePackageIntroducer(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageIntroducer"); +} + +auto SemanticsHandlePackageLibrary(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandlePackageLibrary"); +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_handle_struct.cpp b/toolchain/semantics/semantics_handle_struct.cpp new file mode 100644 index 0000000000000..35de3856f91a2 --- /dev/null +++ b/toolchain/semantics/semantics_handle_struct.cpp @@ -0,0 +1,128 @@ +// 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 "toolchain/semantics/semantics_context.h" + +namespace Carbon { + +auto SemanticsHandleStructComma(SemanticsContext& context, + ParseTree::Node /*parse_node*/) -> bool { + context.ParamOrArgComma( + /*for_args=*/context.parse_tree().node_kind( + context.node_stack().PeekParseNode()) != + ParseNodeKind::StructFieldType); + return true; +} + +auto SemanticsHandleStructFieldDesignator(SemanticsContext& context, + ParseTree::Node /*parse_node*/) + -> bool { + // This leaves the designated name on top because the `.` isn't interesting. + CARBON_CHECK( + context.parse_tree().node_kind(context.node_stack().PeekParseNode()) == + ParseNodeKind::DesignatedName); + return true; +} + +auto SemanticsHandleStructFieldType(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [type_node, type_id] = context.node_stack().PopForParseNodeAndNodeId(); + SemanticsNodeId cast_type_id = context.ImplicitAsRequired( + type_node, type_id, SemanticsNodeId::BuiltinTypeType); + + auto [name_node, name_id] = context.node_stack().PopForParseNodeAndNameId( + ParseNodeKind::DesignatedName); + + context.AddNode( + SemanticsNode::StructTypeField::Make(name_node, cast_type_id, name_id)); + context.node_stack().Push(parse_node); + return true; +} + +auto SemanticsHandleStructFieldUnknown(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + return context.TODO(parse_node, "HandleStructFieldUnknown"); +} + +auto SemanticsHandleStructFieldValue(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [value_parse_node, value_node_id] = + context.node_stack().PopForParseNodeAndNodeId(); + auto [_, name_id] = context.node_stack().PopForParseNodeAndNameId( + ParseNodeKind::DesignatedName); + + // Store the name for the type. + auto type_block_id = context.args_type_info_stack().PeekForAdd(); + context.semantics().AddNode( + type_block_id, + SemanticsNode::StructTypeField::Make( + parse_node, context.semantics().GetNode(value_node_id).type_id(), + name_id)); + + // Push the value back on the stack as an argument. + context.node_stack().Push(parse_node, value_node_id); + return true; +} + +auto SemanticsHandleStructLiteral(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/true, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + + context.PopScope(); + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + auto type_block_id = context.args_type_info_stack().Pop(); + + // Special-case `{}`. + if (refs_id == SemanticsNodeBlockId::Empty) { + context.node_stack().Push(parse_node, SemanticsNodeId::BuiltinEmptyStruct); + return true; + } + + // Construct a type for the literal. Each field is one node, so ir_id and + // refs_id match. + auto refs = context.semantics().GetNodeBlock(refs_id); + auto type_id = context.AddNode(SemanticsNode::StructType::Make( + parse_node, type_block_id, type_block_id)); + + auto value_id = context.AddNode( + SemanticsNode::StructValue::Make(parse_node, type_id, ir_id, refs_id)); + context.node_stack().Push(parse_node, value_id); + return true; +} + +auto SemanticsHandleStructLiteralOrStructTypeLiteralStart( + SemanticsContext& context, ParseTree::Node parse_node) -> bool { + context.PushScope(); + context.node_stack().Push(parse_node); + // At this point we aren't sure whether this will be a value or type literal, + // so we push onto args irrespective. It just won't be used for a type + // literal. + context.args_type_info_stack().Push(); + context.ParamOrArgStart(); + return true; +} + +auto SemanticsHandleStructTypeLiteral(SemanticsContext& context, + ParseTree::Node parse_node) -> bool { + auto [ir_id, refs_id] = context.ParamOrArgEnd( + /*for_args=*/false, ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + + context.PopScope(); + context.node_stack().PopAndDiscardSoloParseNode( + ParseNodeKind::StructLiteralOrStructTypeLiteralStart); + // This is only used for value literals. + context.args_type_info_stack().Pop(); + + CARBON_CHECK(refs_id != SemanticsNodeBlockId::Empty) + << "{} is handled by StructLiteral."; + + auto type_id = context.AddNode( + SemanticsNode::StructType::Make(parse_node, ir_id, refs_id)); + context.node_stack().Push(parse_node, type_id); + return true; +} + +} // namespace Carbon From f1252c79a336ad0b36ef18ad2cd8e2bbcfc61af6 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 21:06:43 +0000 Subject: [PATCH 12/29] x --- toolchain/diagnostics/diagnostic_emitter.h | 38 +++++++++------- .../testdata/semantics_builtin_nodes.carbon} | 1 - .../testdata/semantics_verbose.carbon} | 1 - toolchain/semantics/BUILD | 38 ++++++++++++++++ toolchain/semantics/lit_autoupdate.py | 1 - toolchain/semantics/semantics_file_test.cpp | 45 +++++++++++++++++++ toolchain/semantics/testdata/BUILD | 39 ---------------- .../testdata/basics/builtin_types.carbon | 1 - .../semantics/testdata/basics/empty.carbon | 1 - .../testdata/basics/empty_decl.carbon | 1 - .../testdata/basics/fail_name_lookup.carbon | 1 - .../designators/fail_unsupported.carbon | 1 - .../function/call/empty_struct.carbon | 1 - .../function/call/fail_param_count.carbon | 1 - .../function/call/fail_param_type.carbon | 1 - .../call/fail_return_type_mismatch.carbon | 1 - .../testdata/function/call/i32.carbon | 1 - .../function/call/more_param_ir.carbon | 1 - .../testdata/function/call/params_one.carbon | 1 - .../function/call/params_one_comma.carbon | 1 - .../testdata/function/call/params_two.carbon | 1 - .../function/call/params_two_comma.carbon | 1 - .../testdata/function/call/params_zero.carbon | 1 - .../fail_param_name_conflict.carbon | 1 - .../testdata/function/definition/order.carbon | 1 - .../function/definition/params_one.carbon | 1 - .../definition/params_one_comma.carbon | 1 - .../function/definition/params_two.carbon | 1 - .../definition/params_two_comma.carbon | 1 - .../function/definition/params_zero.carbon | 1 - .../definition/same_param_name.carbon | 1 - .../testdata/operators/binary_op.carbon | 1 - .../operators/fail_type_mismatch.carbon | 1 - .../operators/fail_type_mismatch_once.carbon | 1 - .../testdata/return/fail_type_mismatch.carbon | 1 - .../return/fail_value_disallowed.carbon | 1 - .../testdata/return/fail_value_missing.carbon | 1 - .../semantics/testdata/return/no_value.carbon | 1 - .../semantics/testdata/return/struct.carbon | 1 - .../semantics/testdata/return/value.carbon | 1 - .../semantics/testdata/struct/empty.carbon | 1 - .../testdata/struct/fail_assign_empty.carbon | 1 - .../struct/fail_assign_to_empty.carbon | 1 - .../struct/fail_field_name_mismatch.carbon | 1 - .../struct/fail_field_type_mismatch.carbon | 1 - .../struct/fail_member_access_type.carbon | 1 - .../struct/fail_non_member_access.carbon | 1 - .../struct/fail_too_few_values.carbon | 1 - .../testdata/struct/fail_type_assign.carbon | 1 - .../testdata/struct/fail_value_as_type.carbon | 1 - .../testdata/struct/member_access.carbon | 1 - .../testdata/struct/one_entry.carbon | 1 - .../testdata/struct/two_entries.carbon | 1 - toolchain/semantics/testdata/var/decl.carbon | 1 - .../testdata/var/decl_with_init.carbon | 1 - .../testdata/var/fail_duplicate_decl.carbon | 1 - .../var/fail_init_type_mismatch.carbon | 1 - .../testdata/var/fail_init_with_self.carbon | 1 - .../var/fail_lookup_outside_scope.carbon | 1 - .../var/fail_storage_is_literal.carbon | 1 - .../semantics/testdata/var/global_decl.carbon | 1 - .../testdata/var/global_decl_with_init.carbon | 1 - .../testdata/var/global_lookup.carbon | 1 - .../var/global_lookup_in_scope.carbon | 1 - .../semantics/testdata/var/lookup.carbon | 1 - 65 files changed, 106 insertions(+), 115 deletions(-) rename toolchain/{semantics/testdata/basics/builtin_nodes.carbon => driver/testdata/semantics_builtin_nodes.carbon} (99%) rename toolchain/{semantics/testdata/basics/verbose.carbon => driver/testdata/semantics_verbose.carbon} (97%) create mode 100644 toolchain/semantics/semantics_file_test.cpp delete mode 100644 toolchain/semantics/testdata/BUILD diff --git a/toolchain/diagnostics/diagnostic_emitter.h b/toolchain/diagnostics/diagnostic_emitter.h index 2a1f2299c34ba..a47f3bdd7d455 100644 --- a/toolchain/diagnostics/diagnostic_emitter.h +++ b/toolchain/diagnostics/diagnostic_emitter.h @@ -296,22 +296,30 @@ class DiagnosticEmitter { DiagnosticConsumer* consumer_; }; -inline auto ConsoleDiagnosticConsumer() -> DiagnosticConsumer& { - class Consumer : public DiagnosticConsumer { - auto HandleDiagnostic(Diagnostic diagnostic) -> void override { - Print(diagnostic.message); - for (const auto& note : diagnostic.notes) { - Print(note); - } - } - auto Print(const DiagnosticMessage& message) -> void { - llvm::errs() << message.location.file_name << ":" - << message.location.line_number << ":" - << message.location.column_number << ": " - << message.format_fn(message) << "\n"; +class StreamDiagnosticConsumer : public DiagnosticConsumer { + public: + explicit StreamDiagnosticConsumer(llvm::raw_ostream& stream) + : stream_(&stream) {} + + auto HandleDiagnostic(Diagnostic diagnostic) -> void override { + Print(diagnostic.message); + for (const auto& note : diagnostic.notes) { + Print(note); } - }; - static auto* consumer = new Consumer; + } + auto Print(const DiagnosticMessage& message) -> void { + *stream_ << message.location.file_name << ":" + << message.location.line_number << ":" + << message.location.column_number << ": " + << message.format_fn(message) << "\n"; + } + + private: + llvm::raw_ostream* stream_; +}; + +inline auto ConsoleDiagnosticConsumer() -> DiagnosticConsumer& { + static auto* consumer = new StreamDiagnosticConsumer(llvm::errs()); return *consumer; } diff --git a/toolchain/semantics/testdata/basics/builtin_nodes.carbon b/toolchain/driver/testdata/semantics_builtin_nodes.carbon similarity index 99% rename from toolchain/semantics/testdata/basics/builtin_nodes.carbon rename to toolchain/driver/testdata/semantics_builtin_nodes.carbon index b55ff2042351d..e00d352f57991 100644 --- a/toolchain/semantics/testdata/basics/builtin_nodes.carbon +++ b/toolchain/driver/testdata/semantics_builtin_nodes.carbon @@ -2,7 +2,6 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// NOAUTOUPDATE // RUN: %{carbon} dump semantics-ir --include_builtins %s | \ // RUN: %{FileCheck-strict} // CHECK:STDOUT: cross_reference_irs_size: 1 diff --git a/toolchain/semantics/testdata/basics/verbose.carbon b/toolchain/driver/testdata/semantics_verbose.carbon similarity index 97% rename from toolchain/semantics/testdata/basics/verbose.carbon rename to toolchain/driver/testdata/semantics_verbose.carbon index 13dd078e5804a..6dcce0cf8a302 100644 --- a/toolchain/semantics/testdata/basics/verbose.carbon +++ b/toolchain/driver/testdata/semantics_verbose.carbon @@ -2,7 +2,6 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// NOAUTOUPDATE // RUN: %{carbon} -v dump semantics-ir %s | %{FileCheck-allow-unmatched} // // Only checks a couple statements in order to minimize manual update churn. diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index 9e8761eadf342..eea142aa392f3 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -2,6 +2,9 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +load("//testing/file_test:rules.bzl", "file_test") +load("//bazel/sh_run:rules.bzl", "glob_sh_run") + package(default_visibility = ["//visibility:public"]) cc_library( @@ -105,3 +108,38 @@ cc_test( "@llvm-project//llvm:Support", ], ) + +file_test( + name = "semantics_file_test", + srcs = ["semantics_file_test.cpp"], + tests = glob(["testdata/**/*.carbon"]), + deps = [ + ":semantics_ir", + "//testing/file_test:file_test_base", + "//toolchain/diagnostics:diagnostic_emitter", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "dump", + "semantics-ir", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "-v", + "dump", + "semantics-ir", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], + run_ext = "verbose", +) diff --git a/toolchain/semantics/lit_autoupdate.py b/toolchain/semantics/lit_autoupdate.py index 733a7445f2808..94c714c7b7931 100755 --- a/toolchain/semantics/lit_autoupdate.py +++ b/toolchain/semantics/lit_autoupdate.py @@ -26,7 +26,6 @@ def main() -> None: "--tool=carbon", "--autoupdate_arg=dump", "--autoupdate_arg=semantics-ir", - "--lit_run=%{carbon-run-semantics}", "--testdata=toolchain/semantics/testdata", ] + sys.argv[1:] os.execv(actual_py, args) diff --git a/toolchain/semantics/semantics_file_test.cpp b/toolchain/semantics/semantics_file_test.cpp new file mode 100644 index 0000000000000..6d1ff1799a521 --- /dev/null +++ b/toolchain/semantics/semantics_file_test.cpp @@ -0,0 +1,45 @@ +// 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 +#include + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "testing/file_test/file_test_base.h" +#include "toolchain/diagnostics/diagnostic_emitter.h" +#include "toolchain/semantics/semantics_ir.h" + +namespace Carbon::Testing { +namespace { + +class SemanticsFileTest : public FileTestBase { + public: + explicit SemanticsFileTest(llvm::StringRef path) : FileTestBase(path) {} + + void RunOverFile(llvm::raw_ostream& stdout, + llvm::raw_ostream& stderr) override { + StreamDiagnosticConsumer consumer(stderr); + llvm::Expected source = SourceBuffer::CreateFromFile(path()); + TokenizedBuffer tokens = TokenizedBuffer::Lex(*source, consumer); + ParseTree parse_tree = + ParseTree::Parse(tokens, consumer, /*vlog_stream=*/nullptr); + SemanticsIR builtin_ir = SemanticsIR::MakeBuiltinIR(); + SemanticsIR semantics_ir = SemanticsIR::MakeFromParseTree( + builtin_ir, tokens, parse_tree, consumer, /*vlog_stream=*/nullptr); + semantics_ir.Print(stdout); + } +}; + +} // namespace + +auto RegisterFileTests(const std::vector& paths) -> void { + SemanticsFileTest::RegisterTests( + "SemanticsFileTest", paths, + [](llvm::StringRef path) { return new SemanticsFileTest(path); }); +} + +} // namespace Carbon::Testing diff --git a/toolchain/semantics/testdata/BUILD b/toolchain/semantics/testdata/BUILD deleted file mode 100644 index 5d49323b2b25e..0000000000000 --- a/toolchain/semantics/testdata/BUILD +++ /dev/null @@ -1,39 +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 - -load("//bazel/sh_run:rules.bzl", "glob_sh_run") -load("//bazel/testing:lit.bzl", "glob_lit_tests") - -glob_lit_tests( - data = [ - "//bazel/testing:merge_output", - "//toolchain/driver:carbon", - "@llvm-project//llvm:FileCheck", - "@llvm-project//llvm:not", - ], - driver = "lit.cfg.py", - test_file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "dump", - "semantics-ir", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "-v", - "dump", - "semantics-ir", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], - run_ext = "verbose", -) diff --git a/toolchain/semantics/testdata/basics/builtin_types.carbon b/toolchain/semantics/testdata/basics/builtin_types.carbon index c776fe797dc5b..a0de520f23a54 100644 --- a/toolchain/semantics/testdata/basics/builtin_types.carbon +++ b/toolchain/semantics/testdata/basics/builtin_types.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/basics/empty.carbon b/toolchain/semantics/testdata/basics/empty.carbon index f4f3d951dbdf2..b5c84733c633d 100644 --- a/toolchain/semantics/testdata/basics/empty.carbon +++ b/toolchain/semantics/testdata/basics/empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/basics/empty_decl.carbon b/toolchain/semantics/testdata/basics/empty_decl.carbon index 6083b169b8d2a..aa8e2ea544ea9 100644 --- a/toolchain/semantics/testdata/basics/empty_decl.carbon +++ b/toolchain/semantics/testdata/basics/empty_decl.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/basics/fail_name_lookup.carbon b/toolchain/semantics/testdata/basics/fail_name_lookup.carbon index eb274e706fa05..95d156b4d4eb0 100644 --- a/toolchain/semantics/testdata/basics/fail_name_lookup.carbon +++ b/toolchain/semantics/testdata/basics/fail_name_lookup.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/designators/fail_unsupported.carbon b/toolchain/semantics/testdata/designators/fail_unsupported.carbon index aebc7fa910c14..fa8cc80b938bc 100644 --- a/toolchain/semantics/testdata/designators/fail_unsupported.carbon +++ b/toolchain/semantics/testdata/designators/fail_unsupported.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/empty_struct.carbon b/toolchain/semantics/testdata/function/call/empty_struct.carbon index 089c292a4f014..e41bd9219f7dc 100644 --- a/toolchain/semantics/testdata/function/call/empty_struct.carbon +++ b/toolchain/semantics/testdata/function/call/empty_struct.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, diff --git a/toolchain/semantics/testdata/function/call/fail_param_count.carbon b/toolchain/semantics/testdata/function/call/fail_param_count.carbon index a3ed8bcbb9639..2681174172aed 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_count.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_count.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/fail_param_type.carbon b/toolchain/semantics/testdata/function/call/fail_param_type.carbon index 18a5f4260bc6c..603a72e0b999b 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_type.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon b/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon index 886576cbf6778..a40c6ec6fbf56 100644 --- a/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon +++ b/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block0, arg_refs: block0}, diff --git a/toolchain/semantics/testdata/function/call/i32.carbon b/toolchain/semantics/testdata/function/call/i32.carbon index 86e2a2cb318c4..3b34c8164f372 100644 --- a/toolchain/semantics/testdata/function/call/i32.carbon +++ b/toolchain/semantics/testdata/function/call/i32.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block6, arg_refs: block7}, diff --git a/toolchain/semantics/testdata/function/call/more_param_ir.carbon b/toolchain/semantics/testdata/function/call/more_param_ir.carbon index 415df0671de22..f871a07b352a9 100644 --- a/toolchain/semantics/testdata/function/call/more_param_ir.carbon +++ b/toolchain/semantics/testdata/function/call/more_param_ir.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, diff --git a/toolchain/semantics/testdata/function/call/params_one.carbon b/toolchain/semantics/testdata/function/call/params_one.carbon index 95f58315e90bf..51f27f0b7e861 100644 --- a/toolchain/semantics/testdata/function/call/params_one.carbon +++ b/toolchain/semantics/testdata/function/call/params_one.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, diff --git a/toolchain/semantics/testdata/function/call/params_one_comma.carbon b/toolchain/semantics/testdata/function/call/params_one_comma.carbon index 76cb014fa87a1..28b63c387448f 100644 --- a/toolchain/semantics/testdata/function/call/params_one_comma.carbon +++ b/toolchain/semantics/testdata/function/call/params_one_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, diff --git a/toolchain/semantics/testdata/function/call/params_two.carbon b/toolchain/semantics/testdata/function/call/params_two.carbon index a99f0b8b17967..5b437930a77a1 100644 --- a/toolchain/semantics/testdata/function/call/params_two.carbon +++ b/toolchain/semantics/testdata/function/call/params_two.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, diff --git a/toolchain/semantics/testdata/function/call/params_two_comma.carbon b/toolchain/semantics/testdata/function/call/params_two_comma.carbon index 0a1447c4ba4f1..02935c7188a90 100644 --- a/toolchain/semantics/testdata/function/call/params_two_comma.carbon +++ b/toolchain/semantics/testdata/function/call/params_two_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block4, arg_refs: block5}, diff --git a/toolchain/semantics/testdata/function/call/params_zero.carbon b/toolchain/semantics/testdata/function/call/params_zero.carbon index aabccb5d8e621..072743c05a62d 100644 --- a/toolchain/semantics/testdata/function/call/params_zero.carbon +++ b/toolchain/semantics/testdata/function/call/params_zero.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: {arg_ir: block0, arg_refs: block0}, diff --git a/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon b/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon index 0d2c4572e50b4..2fce6496aab0e 100644 --- a/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon +++ b/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/order.carbon b/toolchain/semantics/testdata/function/definition/order.carbon index 40e84ef35b6b9..33c07ed39c665 100644 --- a/toolchain/semantics/testdata/function/definition/order.carbon +++ b/toolchain/semantics/testdata/function/definition/order.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/params_one.carbon b/toolchain/semantics/testdata/function/definition/params_one.carbon index 85fa950d6dd4f..227ac2c9feecc 100644 --- a/toolchain/semantics/testdata/function/definition/params_one.carbon +++ b/toolchain/semantics/testdata/function/definition/params_one.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/params_one_comma.carbon b/toolchain/semantics/testdata/function/definition/params_one_comma.carbon index 69cb8d98c819b..c9862f4c93629 100644 --- a/toolchain/semantics/testdata/function/definition/params_one_comma.carbon +++ b/toolchain/semantics/testdata/function/definition/params_one_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/params_two.carbon b/toolchain/semantics/testdata/function/definition/params_two.carbon index 3ba5754c78032..babb726b2a071 100644 --- a/toolchain/semantics/testdata/function/definition/params_two.carbon +++ b/toolchain/semantics/testdata/function/definition/params_two.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/params_two_comma.carbon b/toolchain/semantics/testdata/function/definition/params_two_comma.carbon index 3d955513f3776..0cd2d9b6b547e 100644 --- a/toolchain/semantics/testdata/function/definition/params_two_comma.carbon +++ b/toolchain/semantics/testdata/function/definition/params_two_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/params_zero.carbon b/toolchain/semantics/testdata/function/definition/params_zero.carbon index 5e410d7ec49b4..f9d6279fc7e92 100644 --- a/toolchain/semantics/testdata/function/definition/params_zero.carbon +++ b/toolchain/semantics/testdata/function/definition/params_zero.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/function/definition/same_param_name.carbon b/toolchain/semantics/testdata/function/definition/same_param_name.carbon index 5fa87ce323a07..a83ddb17ece46 100644 --- a/toolchain/semantics/testdata/function/definition/same_param_name.carbon +++ b/toolchain/semantics/testdata/function/definition/same_param_name.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/operators/binary_op.carbon b/toolchain/semantics/testdata/operators/binary_op.carbon index 47d33e6c229a4..c9831eedbb3be 100644 --- a/toolchain/semantics/testdata/operators/binary_op.carbon +++ b/toolchain/semantics/testdata/operators/binary_op.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon index e13ffd5db76ab..44a379c79b628 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon index 314d14bbee11b..2730a8a975150 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/return/fail_type_mismatch.carbon b/toolchain/semantics/testdata/return/fail_type_mismatch.carbon index e82ab651045e4..44d7bb6d5b339 100644 --- a/toolchain/semantics/testdata/return/fail_type_mismatch.carbon +++ b/toolchain/semantics/testdata/return/fail_type_mismatch.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/return/fail_value_disallowed.carbon b/toolchain/semantics/testdata/return/fail_value_disallowed.carbon index 0d2730826545c..bdbe7de1dc787 100644 --- a/toolchain/semantics/testdata/return/fail_value_disallowed.carbon +++ b/toolchain/semantics/testdata/return/fail_value_disallowed.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/return/fail_value_missing.carbon b/toolchain/semantics/testdata/return/fail_value_missing.carbon index b671d56ab67cc..e3b20376c6af0 100644 --- a/toolchain/semantics/testdata/return/fail_value_missing.carbon +++ b/toolchain/semantics/testdata/return/fail_value_missing.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/return/no_value.carbon b/toolchain/semantics/testdata/return/no_value.carbon index e3ec3b16f8e8f..042c37b6531c0 100644 --- a/toolchain/semantics/testdata/return/no_value.carbon +++ b/toolchain/semantics/testdata/return/no_value.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/return/struct.carbon b/toolchain/semantics/testdata/return/struct.carbon index b2e8f11d03052..c0f6bcf00c447 100644 --- a/toolchain/semantics/testdata/return/struct.carbon +++ b/toolchain/semantics/testdata/return/struct.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/return/value.carbon b/toolchain/semantics/testdata/return/value.carbon index 848e6534c9be6..f07fce59bd939 100644 --- a/toolchain/semantics/testdata/return/value.carbon +++ b/toolchain/semantics/testdata/return/value.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/empty.carbon b/toolchain/semantics/testdata/struct/empty.carbon index 765efd01ae911..0ba80fee761a1 100644 --- a/toolchain/semantics/testdata/struct/empty.carbon +++ b/toolchain/semantics/testdata/struct/empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_assign_empty.carbon b/toolchain/semantics/testdata/struct/fail_assign_empty.carbon index cb8405cab90d6..f5fd77bbdd2f7 100644 --- a/toolchain/semantics/testdata/struct/fail_assign_empty.carbon +++ b/toolchain/semantics/testdata/struct/fail_assign_empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon b/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon index c40af0b19e53c..6f40119aa38c5 100644 --- a/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon +++ b/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon b/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon index 9cb10d8c057c8..dd3d35b571abc 100644 --- a/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon +++ b/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon b/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon index f2b0e38168de2..2503fedf32ee2 100644 --- a/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon +++ b/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_member_access_type.carbon b/toolchain/semantics/testdata/struct/fail_member_access_type.carbon index 73d15c3ca9bf1..1072d5914a1a3 100644 --- a/toolchain/semantics/testdata/struct/fail_member_access_type.carbon +++ b/toolchain/semantics/testdata/struct/fail_member_access_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_non_member_access.carbon b/toolchain/semantics/testdata/struct/fail_non_member_access.carbon index 3c24a00b8915e..fb28b019aeb3b 100644 --- a/toolchain/semantics/testdata/struct/fail_non_member_access.carbon +++ b/toolchain/semantics/testdata/struct/fail_non_member_access.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_too_few_values.carbon b/toolchain/semantics/testdata/struct/fail_too_few_values.carbon index ebfffb7f5c69f..86e0d5f98fd31 100644 --- a/toolchain/semantics/testdata/struct/fail_too_few_values.carbon +++ b/toolchain/semantics/testdata/struct/fail_too_few_values.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_type_assign.carbon b/toolchain/semantics/testdata/struct/fail_type_assign.carbon index 8bfe0d064b6f5..9a625713be627 100644 --- a/toolchain/semantics/testdata/struct/fail_type_assign.carbon +++ b/toolchain/semantics/testdata/struct/fail_type_assign.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/fail_value_as_type.carbon b/toolchain/semantics/testdata/struct/fail_value_as_type.carbon index 39e917ef28783..40983c0e1fc13 100644 --- a/toolchain/semantics/testdata/struct/fail_value_as_type.carbon +++ b/toolchain/semantics/testdata/struct/fail_value_as_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/member_access.carbon b/toolchain/semantics/testdata/struct/member_access.carbon index 19f8f238994be..fed78e2522629 100644 --- a/toolchain/semantics/testdata/struct/member_access.carbon +++ b/toolchain/semantics/testdata/struct/member_access.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/one_entry.carbon b/toolchain/semantics/testdata/struct/one_entry.carbon index e48f76eccb477..3156d99d64710 100644 --- a/toolchain/semantics/testdata/struct/one_entry.carbon +++ b/toolchain/semantics/testdata/struct/one_entry.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/struct/two_entries.carbon b/toolchain/semantics/testdata/struct/two_entries.carbon index 20e4fdb0df09f..06ae45bb219ac 100644 --- a/toolchain/semantics/testdata/struct/two_entries.carbon +++ b/toolchain/semantics/testdata/struct/two_entries.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/decl.carbon b/toolchain/semantics/testdata/var/decl.carbon index feecfabc78aa7..d6fb83534b1ec 100644 --- a/toolchain/semantics/testdata/var/decl.carbon +++ b/toolchain/semantics/testdata/var/decl.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/decl_with_init.carbon b/toolchain/semantics/testdata/var/decl_with_init.carbon index b76d7ca5c24a3..e00d1cad804c5 100644 --- a/toolchain/semantics/testdata/var/decl_with_init.carbon +++ b/toolchain/semantics/testdata/var/decl_with_init.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon b/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon index 3fb5bad9d75ec..69307f8b1a381 100644 --- a/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon +++ b/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon b/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon index a076142a327b9..0e4964f07eb23 100644 --- a/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon +++ b/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/fail_init_with_self.carbon b/toolchain/semantics/testdata/var/fail_init_with_self.carbon index 0961dce53618b..e9bcc63e4765a 100644 --- a/toolchain/semantics/testdata/var/fail_init_with_self.carbon +++ b/toolchain/semantics/testdata/var/fail_init_with_self.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon b/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon index 842728ff7000b..7304038c35198 100644 --- a/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon +++ b/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon b/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon index 3511c9c8c7c6a..50254d0e77bd9 100644 --- a/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon +++ b/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/global_decl.carbon b/toolchain/semantics/testdata/var/global_decl.carbon index a1fe3ea46a48e..7e9a115d4f1b5 100644 --- a/toolchain/semantics/testdata/var/global_decl.carbon +++ b/toolchain/semantics/testdata/var/global_decl.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/global_decl_with_init.carbon b/toolchain/semantics/testdata/var/global_decl_with_init.carbon index 9c701da382758..2e823efb0727b 100644 --- a/toolchain/semantics/testdata/var/global_decl_with_init.carbon +++ b/toolchain/semantics/testdata/var/global_decl_with_init.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/global_lookup.carbon b/toolchain/semantics/testdata/var/global_lookup.carbon index b1ba45fe5e9fb..baffba6baf100 100644 --- a/toolchain/semantics/testdata/var/global_lookup.carbon +++ b/toolchain/semantics/testdata/var/global_lookup.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/global_lookup_in_scope.carbon b/toolchain/semantics/testdata/var/global_lookup_in_scope.carbon index 22074aa6f05a1..f7a1625e50a18 100644 --- a/toolchain/semantics/testdata/var/global_lookup_in_scope.carbon +++ b/toolchain/semantics/testdata/var/global_lookup_in_scope.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/var/lookup.carbon b/toolchain/semantics/testdata/var/lookup.carbon index a5fa9e2ea1f7d..d76b6413f9e4b 100644 --- a/toolchain/semantics/testdata/var/lookup.carbon +++ b/toolchain/semantics/testdata/var/lookup.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-semantics} // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: calls: [ // CHECK:STDOUT: ] From b219add3fdd96c9c723d4131dec9b195dc2049df Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 21:14:40 +0000 Subject: [PATCH 13/29] Path handling --- bazel/testing/lit_autoupdate_base.py | 23 ++++++++++------------- testing/file_test/file_test_base.cpp | 6 ------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/bazel/testing/lit_autoupdate_base.py b/bazel/testing/lit_autoupdate_base.py index 36aaffbc7bd05..647b6266e73ba 100755 --- a/bazel/testing/lit_autoupdate_base.py +++ b/bazel/testing/lit_autoupdate_base.py @@ -295,6 +295,7 @@ def replace_all(s: str, replacements: List[Tuple[str, str]]) -> str: def get_matchable_test_output( autoupdate_args: List[str], + for_lit: bool, extra_check_replacements: List[Tuple[Pattern, Pattern, str]], tool: str, bazel_runfiles: Pattern, @@ -312,21 +313,16 @@ def get_matchable_test_output( encoding="utf-8", ).stdout + # Escape things that mirror FileCheck special characters. + out = out.replace("{{", "{{[{][{]}}") + out = out.replace("[[", "{{[[][[]}}") # `lit` uses full paths to the test file, so use a regex to ignore paths # when used. - out = replace_all( - out, - [ - ("{{", "{{[{][{]}}"), - ("[[", "{{[[][[]}}"), - # TODO: Maybe revisit and see if lit can be convinced to give a - # root-relative path. - (test, f"{{{{.*}}}}/{test}"), - ], - ) - # Replacing runfiles is a more complex replacement. - # We have some things show up under runfiles; this removes them. - out = bazel_runfiles.sub("{{.*}}/", out) + if for_lit: + out = out.replace(test, f"{{{{.*}}}}/{test}") + # Replacing runfiles is a more complex replacement. + # We have some things show up under runfiles; this removes them. + out = bazel_runfiles.sub("{{.*}}/", out) out_lines = out.splitlines() for i, line in enumerate(out_lines): @@ -413,6 +409,7 @@ def update_check( # Determine the merged output lines. out_lines = get_matchable_test_output( parsed_args.autoupdate_args, + bool(parsed_args.lit_run), parsed_args.extra_check_replacements, parsed_args.tool, bazel_runfiles, diff --git a/testing/file_test/file_test_base.cpp b/testing/file_test/file_test_base.cpp index 0b4fe760cd4b0..951cada90eaff 100644 --- a/testing/file_test/file_test_base.cpp +++ b/testing/file_test/file_test_base.cpp @@ -138,16 +138,10 @@ auto FileTestBase::TransformExpectation(int line_index, llvm::StringRef in) break; } case '{': { - static constexpr llvm::StringLiteral PathBefore = "{{.*}}/explorer/"; - static constexpr llvm::StringLiteral PathAfter = "explorer/"; if (pos + 1 == static_cast(str.size()) || str[pos + 1] != '{') { // Single `{`, escape it. str.insert(pos, "\\"); pos += 2; - } else if (llvm::StringRef(str).substr(pos).starts_with(PathBefore)) { - str.replace(pos, PathBefore.size(), PathAfter); - // Move the position; the loop still increments position by 1. - pos += PathAfter.size(); } else { // Replace the `{{...}}` regex syntax with standard `(...)` syntax. str.replace(pos, 2, "("); From e769e0120157e541229468993b7d4b736419ac17 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 21:15:59 +0000 Subject: [PATCH 14/29] tests --- .../testdata/basics/fail_name_lookup.carbon | 2 +- .../designators/fail_unsupported.carbon | 2 +- .../function/call/fail_param_count.carbon | 24 +++++++++---------- .../function/call/fail_param_type.carbon | 4 ++-- .../call/fail_return_type_mismatch.carbon | 2 +- .../fail_param_name_conflict.carbon | 4 ++-- .../operators/fail_type_mismatch.carbon | 2 +- .../operators/fail_type_mismatch_once.carbon | 2 +- .../testdata/return/fail_type_mismatch.carbon | 2 +- .../return/fail_value_disallowed.carbon | 4 ++-- .../testdata/return/fail_value_missing.carbon | 2 +- .../testdata/struct/fail_assign_empty.carbon | 2 +- .../struct/fail_assign_to_empty.carbon | 2 +- .../struct/fail_field_name_mismatch.carbon | 2 +- .../struct/fail_field_type_mismatch.carbon | 2 +- .../struct/fail_member_access_type.carbon | 2 +- .../struct/fail_non_member_access.carbon | 2 +- .../struct/fail_too_few_values.carbon | 2 +- .../testdata/struct/fail_type_assign.carbon | 2 +- .../testdata/struct/fail_value_as_type.carbon | 2 +- .../testdata/var/fail_duplicate_decl.carbon | 4 ++-- .../var/fail_init_type_mismatch.carbon | 2 +- .../testdata/var/fail_init_with_self.carbon | 2 +- .../var/fail_lookup_outside_scope.carbon | 2 +- .../var/fail_storage_is_literal.carbon | 2 +- 25 files changed, 40 insertions(+), 40 deletions(-) diff --git a/toolchain/semantics/testdata/basics/fail_name_lookup.carbon b/toolchain/semantics/testdata/basics/fail_name_lookup.carbon index 95d156b4d4eb0..ba0bee0e4effe 100644 --- a/toolchain/semantics/testdata/basics/fail_name_lookup.carbon +++ b/toolchain/semantics/testdata/basics/fail_name_lookup.carbon @@ -30,6 +30,6 @@ // CHECK:STDOUT: ] fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/basics/fail_name_lookup.carbon:[[@LINE+1]]:3: Name x not found + // CHECK:STDERR: toolchain/semantics/testdata/basics/fail_name_lookup.carbon:[[@LINE+1]]:3: Name x not found x; } diff --git a/toolchain/semantics/testdata/designators/fail_unsupported.carbon b/toolchain/semantics/testdata/designators/fail_unsupported.carbon index fa8cc80b938bc..d7160ec24e85c 100644 --- a/toolchain/semantics/testdata/designators/fail_unsupported.carbon +++ b/toolchain/semantics/testdata/designators/fail_unsupported.carbon @@ -37,5 +37,5 @@ // CHECK:STDOUT: ] var x: i32; -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/designators/fail_unsupported.carbon:[[@LINE+1]]:15: Type `i32` does not support designator expressions. +// CHECK:STDERR: toolchain/semantics/testdata/designators/fail_unsupported.carbon:[[@LINE+1]]:15: Type `i32` does not support designator expressions. var y: i32 = x.b; diff --git a/toolchain/semantics/testdata/function/call/fail_param_count.carbon b/toolchain/semantics/testdata/function/call/fail_param_count.carbon index 2681174172aed..1d3cd6ed9c3fc 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_count.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_count.carbon @@ -129,24 +129,24 @@ fn Run1(a: i32) {} fn Run2(a: i32, b: i32) {} fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-6]]:1: Callable cannot be used: Received 1 argument(s), but require 0 argument(s). + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-6]]:1: Callable cannot be used: Received 1 argument(s), but require 0 argument(s). Run0(1); - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-9]]:1: Callable cannot be used: Received 2 argument(s), but require 0 argument(s). + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-9]]:1: Callable cannot be used: Received 2 argument(s), but require 0 argument(s). Run0(0, 1); - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-12]]:1: Callable cannot be used: Received 0 argument(s), but require 1 argument(s). + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-12]]:1: Callable cannot be used: Received 0 argument(s), but require 1 argument(s). Run1(); - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-15]]:1: Callable cannot be used: Received 2 argument(s), but require 1 argument(s). + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-15]]:1: Callable cannot be used: Received 2 argument(s), but require 1 argument(s). Run1(0, 1); - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-18]]:1: Callable cannot be used: Received 0 argument(s), but require 2 argument(s). + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-18]]:1: Callable cannot be used: Received 0 argument(s), but require 2 argument(s). Run2(); - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-21]]:1: Callable cannot be used: Received 1 argument(s), but require 2 argument(s). + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE+2]]:7: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_count.carbon:[[@LINE-21]]:1: Callable cannot be used: Received 1 argument(s), but require 2 argument(s). Run2(0); } diff --git a/toolchain/semantics/testdata/function/call/fail_param_type.carbon b/toolchain/semantics/testdata/function/call/fail_param_type.carbon index 603a72e0b999b..5bd11eb25f20e 100644 --- a/toolchain/semantics/testdata/function/call/fail_param_type.carbon +++ b/toolchain/semantics/testdata/function/call/fail_param_type.carbon @@ -58,7 +58,7 @@ fn Run(a: i32) {} fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_type.carbon:[[@LINE+2]]:6: No matching callable was found. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_param_type.carbon:[[@LINE-4]]:1: Callable cannot be used: Cannot implicityly convert argument 0 from `f64` to `i32`. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_type.carbon:[[@LINE+2]]:6: No matching callable was found. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_param_type.carbon:[[@LINE-4]]:1: Callable cannot be used: Cannot implicityly convert argument 0 from `f64` to `i32`. Run(1.0); } diff --git a/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon b/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon index a40c6ec6fbf56..2b540d2c8026a 100644 --- a/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon +++ b/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon @@ -57,6 +57,6 @@ fn Foo() -> f64 { return 1.0; } fn Run() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon:[[@LINE+1]]:21: Cannot implicitly convert from `f64` to `i32`. + // CHECK:STDERR: toolchain/semantics/testdata/function/call/fail_return_type_mismatch.carbon:[[@LINE+1]]:21: Cannot implicitly convert from `f64` to `i32`. var x: i32 = Foo(); } diff --git a/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon b/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon index 2fce6496aab0e..5c127c0c85cec 100644 --- a/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon +++ b/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon @@ -44,6 +44,6 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon:[[@LINE+2]]:16: Redefining a in the same scope. -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon:[[@LINE+1]]:8: Previous definition is here. +// CHECK:STDERR: toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon:[[@LINE+2]]:16: Redefining a in the same scope. +// CHECK:STDERR: toolchain/semantics/testdata/function/definition/fail_param_name_conflict.carbon:[[@LINE+1]]:8: Previous definition is here. fn Bar(a: i32, a: i32) {} diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon index 44a379c79b628..b375acea7d212 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon @@ -42,6 +42,6 @@ // CHECK:STDOUT: ] fn Main() -> i32 { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon:[[@LINE+1]]:13: Cannot implicitly convert from `i32` to `f64`. + // CHECK:STDERR: toolchain/semantics/testdata/operators/fail_type_mismatch.carbon:[[@LINE+1]]:13: Cannot implicitly convert from `i32` to `f64`. return 12 + 3.4; } diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon index 2730a8a975150..c77b6209dd26b 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon @@ -49,6 +49,6 @@ fn Main() -> i32 { // The following line has two mismatches, but after the first, it shouldn't // keep erroring. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon:[[@LINE+1]]:13: Cannot implicitly convert from `i32` to `f64`. + // CHECK:STDERR: toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon:[[@LINE+1]]:13: Cannot implicitly convert from `i32` to `f64`. return 12 + 3.4 + 12; } diff --git a/toolchain/semantics/testdata/return/fail_type_mismatch.carbon b/toolchain/semantics/testdata/return/fail_type_mismatch.carbon index 44d7bb6d5b339..65c8e949ab068 100644 --- a/toolchain/semantics/testdata/return/fail_type_mismatch.carbon +++ b/toolchain/semantics/testdata/return/fail_type_mismatch.carbon @@ -37,6 +37,6 @@ // CHECK:STDOUT: ] fn Main() -> i32 { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_type_mismatch.carbon:[[@LINE+1]]:13: Cannot implicitly convert from `f64` to `i32`. + // CHECK:STDERR: toolchain/semantics/testdata/return/fail_type_mismatch.carbon:[[@LINE+1]]:13: Cannot implicitly convert from `f64` to `i32`. return 1.0; } diff --git a/toolchain/semantics/testdata/return/fail_value_disallowed.carbon b/toolchain/semantics/testdata/return/fail_value_disallowed.carbon index bdbe7de1dc787..8fa4b6157e5ab 100644 --- a/toolchain/semantics/testdata/return/fail_value_disallowed.carbon +++ b/toolchain/semantics/testdata/return/fail_value_disallowed.carbon @@ -37,7 +37,7 @@ // CHECK:STDOUT: ] fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_value_disallowed.carbon:[[@LINE+2]]:11: No return expression should be provided in this context. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_value_disallowed.carbon:[[@LINE-2]]:1: There was no return type provided. + // CHECK:STDERR: toolchain/semantics/testdata/return/fail_value_disallowed.carbon:[[@LINE+2]]:11: No return expression should be provided in this context. + // CHECK:STDERR: toolchain/semantics/testdata/return/fail_value_disallowed.carbon:[[@LINE-2]]:1: There was no return type provided. return 0; } diff --git a/toolchain/semantics/testdata/return/fail_value_missing.carbon b/toolchain/semantics/testdata/return/fail_value_missing.carbon index e3b20376c6af0..d3c20ef56275f 100644 --- a/toolchain/semantics/testdata/return/fail_value_missing.carbon +++ b/toolchain/semantics/testdata/return/fail_value_missing.carbon @@ -34,6 +34,6 @@ // CHECK:STDOUT: ] fn Main() -> i32 { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/return/fail_value_missing.carbon:[[@LINE+1]]:9: Must return a i32. + // CHECK:STDERR: toolchain/semantics/testdata/return/fail_value_missing.carbon:[[@LINE+1]]:9: Must return a i32. return; } diff --git a/toolchain/semantics/testdata/struct/fail_assign_empty.carbon b/toolchain/semantics/testdata/struct/fail_assign_empty.carbon index f5fd77bbdd2f7..d2caf14598758 100644 --- a/toolchain/semantics/testdata/struct/fail_assign_empty.carbon +++ b/toolchain/semantics/testdata/struct/fail_assign_empty.carbon @@ -40,5 +40,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_assign_empty.carbon:[[@LINE+1]]:22: Cannot implicitly convert from `{} as Type` to `{.a: i32}`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_assign_empty.carbon:[[@LINE+1]]:22: Cannot implicitly convert from `{} as Type` to `{.a: i32}`. var x: {.a: i32} = {}; diff --git a/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon b/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon index 6f40119aa38c5..6a88a2bdbf3a5 100644 --- a/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon +++ b/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon @@ -49,5 +49,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon:[[@LINE+1]]:21: Cannot implicitly convert from `{.a: i32}` to `{} as Type`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_assign_to_empty.carbon:[[@LINE+1]]:21: Cannot implicitly convert from `{.a: i32}` to `{} as Type`. var x: {} = {.a = 1}; diff --git a/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon b/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon index dd3d35b571abc..a84080b558d35 100644 --- a/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon +++ b/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon @@ -59,5 +59,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon:[[@LINE+1]]:28: Cannot implicitly convert from `{.b: i32}` to `{.a: i32}`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_field_name_mismatch.carbon:[[@LINE+1]]:28: Cannot implicitly convert from `{.b: i32}` to `{.a: i32}`. var x: {.a: i32} = {.b = 1}; diff --git a/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon b/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon index 2503fedf32ee2..8142e48a49208 100644 --- a/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon +++ b/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon @@ -59,5 +59,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon:[[@LINE+1]]:30: Cannot implicitly convert from `{.b: f64}` to `{.a: i32}`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_field_type_mismatch.carbon:[[@LINE+1]]:30: Cannot implicitly convert from `{.b: f64}` to `{.a: i32}`. var x: {.a: i32} = {.b = 1.0}; diff --git a/toolchain/semantics/testdata/struct/fail_member_access_type.carbon b/toolchain/semantics/testdata/struct/fail_member_access_type.carbon index 1072d5914a1a3..ef4f9b98db831 100644 --- a/toolchain/semantics/testdata/struct/fail_member_access_type.carbon +++ b/toolchain/semantics/testdata/struct/fail_member_access_type.carbon @@ -67,5 +67,5 @@ // CHECK:STDOUT: ] var x: {.a: f64} = {.a = 4.0}; -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_member_access_type.carbon:[[@LINE+1]]:15: Type `{.a: f64}` does not have a member `b`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_member_access_type.carbon:[[@LINE+1]]:15: Type `{.a: f64}` does not have a member `b`. var y: i32 = x.b; diff --git a/toolchain/semantics/testdata/struct/fail_non_member_access.carbon b/toolchain/semantics/testdata/struct/fail_non_member_access.carbon index fb28b019aeb3b..1d18c87280683 100644 --- a/toolchain/semantics/testdata/struct/fail_non_member_access.carbon +++ b/toolchain/semantics/testdata/struct/fail_non_member_access.carbon @@ -67,5 +67,5 @@ // CHECK:STDOUT: ] var x: {.a: i32} = {.a = 4}; -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_non_member_access.carbon:[[@LINE+1]]:15: Type `{.a: i32}` does not have a member `b`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_non_member_access.carbon:[[@LINE+1]]:15: Type `{.a: i32}` does not have a member `b`. var y: i32 = x.b; diff --git a/toolchain/semantics/testdata/struct/fail_too_few_values.carbon b/toolchain/semantics/testdata/struct/fail_too_few_values.carbon index 86e0d5f98fd31..83ce18c72b320 100644 --- a/toolchain/semantics/testdata/struct/fail_too_few_values.carbon +++ b/toolchain/semantics/testdata/struct/fail_too_few_values.carbon @@ -62,5 +62,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_too_few_values.carbon:[[@LINE+1]]:37: Cannot implicitly convert from `{.a: i32}` to `{.a: i32, .b: i32}`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_too_few_values.carbon:[[@LINE+1]]:37: Cannot implicitly convert from `{.a: i32}` to `{.a: i32, .b: i32}`. var x: {.a: i32, .b: i32} = {.a = 1}; diff --git a/toolchain/semantics/testdata/struct/fail_type_assign.carbon b/toolchain/semantics/testdata/struct/fail_type_assign.carbon index 9a625713be627..15e54bc359ce2 100644 --- a/toolchain/semantics/testdata/struct/fail_type_assign.carbon +++ b/toolchain/semantics/testdata/struct/fail_type_assign.carbon @@ -49,5 +49,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_type_assign.carbon:[[@LINE+1]]:29: Cannot implicitly convert from `Type` to `{.a: i32}`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_type_assign.carbon:[[@LINE+1]]:29: Cannot implicitly convert from `Type` to `{.a: i32}`. var x: {.a: i32} = {.a: i32}; diff --git a/toolchain/semantics/testdata/struct/fail_value_as_type.carbon b/toolchain/semantics/testdata/struct/fail_value_as_type.carbon index 40983c0e1fc13..1e7ee601fec6b 100644 --- a/toolchain/semantics/testdata/struct/fail_value_as_type.carbon +++ b/toolchain/semantics/testdata/struct/fail_value_as_type.carbon @@ -47,5 +47,5 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/struct/fail_value_as_type.carbon:[[@LINE+1]]:15: Cannot implicitly convert from `{.a: i32}` to `Type`. +// CHECK:STDERR: toolchain/semantics/testdata/struct/fail_value_as_type.carbon:[[@LINE+1]]:15: Cannot implicitly convert from `{.a: i32}` to `Type`. var x: {.a = 1}; diff --git a/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon b/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon index 69307f8b1a381..4de435507dcc5 100644 --- a/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon +++ b/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon @@ -53,7 +53,7 @@ fn Main() { var x: i32 = 0; - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon:[[@LINE+2]]:7: Redefining x in the same scope. - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_duplicate_decl.carbon:[[@LINE-2]]:7: Previous definition is here. + // CHECK:STDERR: toolchain/semantics/testdata/var/fail_duplicate_decl.carbon:[[@LINE+2]]:7: Redefining x in the same scope. + // CHECK:STDERR: toolchain/semantics/testdata/var/fail_duplicate_decl.carbon:[[@LINE-2]]:7: Previous definition is here. var x: i32 = 0; } diff --git a/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon b/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon index 0e4964f07eb23..32c730ea88bd2 100644 --- a/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon +++ b/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon @@ -42,6 +42,6 @@ // CHECK:STDOUT: ] fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon:[[@LINE+1]]:19: Cannot implicitly convert from `f64` to `i32`. + // CHECK:STDERR: toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon:[[@LINE+1]]:19: Cannot implicitly convert from `f64` to `i32`. var x: i32 = 1.0; } diff --git a/toolchain/semantics/testdata/var/fail_init_with_self.carbon b/toolchain/semantics/testdata/var/fail_init_with_self.carbon index e9bcc63e4765a..1a1c17fd98884 100644 --- a/toolchain/semantics/testdata/var/fail_init_with_self.carbon +++ b/toolchain/semantics/testdata/var/fail_init_with_self.carbon @@ -39,6 +39,6 @@ // CHECK:STDOUT: ] fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_init_with_self.carbon:[[@LINE+1]]:16: Name x not found + // CHECK:STDERR: toolchain/semantics/testdata/var/fail_init_with_self.carbon:[[@LINE+1]]:16: Name x not found var x: i32 = x; } diff --git a/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon b/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon index 7304038c35198..1b2768ec9ec66 100644 --- a/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon +++ b/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon @@ -47,5 +47,5 @@ fn Main() { var x: i32; } -// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon:[[@LINE+1]]:14: Name x not found +// CHECK:STDERR: toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon:[[@LINE+1]]:14: Name x not found var y: i32 = x; diff --git a/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon b/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon index 50254d0e77bd9..5f8d808dfad46 100644 --- a/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon +++ b/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon @@ -45,6 +45,6 @@ // CHECK:STDOUT: ] fn Main() { - // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_storage_is_literal.carbon:[[@LINE+1]]:10: Cannot implicitly convert from `i32` to `Type`. + // CHECK:STDERR: toolchain/semantics/testdata/var/fail_storage_is_literal.carbon:[[@LINE+1]]:10: Cannot implicitly convert from `i32` to `Type`. var x: 1 = 1; } From a100082c68472f9fd27f9ce48ec6b1279a45211d Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 22:10:56 +0000 Subject: [PATCH 15/29] x --- toolchain/driver/BUILD | 2 - toolchain/driver/driver.cpp | 4 +- toolchain/lexer/BUILD | 24 ++++++++++++ toolchain/lexer/lexer_file_test.cpp | 37 ++++++++++++++++++ toolchain/lexer/lit_autoupdate.py | 1 - toolchain/lexer/testdata/BUILD | 27 ------------- toolchain/lexer/testdata/carbon_test.carbon | 1 - toolchain/lexer/testdata/lit.cfg.py | 1 - toolchain/lowering/BUILD | 37 ++++++++++++++++++ toolchain/lowering/lit_autoupdate.py | 1 - toolchain/lowering/lowering_file_test.cpp | 37 ++++++++++++++++++ toolchain/lowering/testdata/BUILD | 39 ------------------- .../lowering/testdata/basics/empty.carbon | 5 +-- .../basics/fail_before_lowering.carbon | 3 +- .../lowering/testdata/basics/zero.carbon | 5 +-- .../function/definition/params_one.carbon | 5 +-- .../function/definition/params_two.carbon | 5 +-- .../function/definition/params_zero.carbon | 5 +-- toolchain/lowering/testdata/lit.cfg.py | 1 - .../lowering/testdata/return/no_value.carbon | 5 +-- .../lowering/testdata/return/value.carbon | 5 +-- toolchain/parser/BUILD | 36 +++++++++++++++++ toolchain/parser/lit_autoupdate.py | 1 - toolchain/parser/parse_tree_file_test.cpp | 37 ++++++++++++++++++ toolchain/parser/testdata/BUILD | 39 ------------------- .../testdata/basics/builtin_types.carbon | 1 - toolchain/parser/testdata/basics/empty.carbon | 1 - .../testdata/basics/empty_declaration.carbon | 1 - .../basics/fail_invalid_designators.carbon | 7 ++-- .../basics/fail_no_intro_with_semi.carbon | 3 +- .../basics/fail_no_intro_without_semi.carbon | 3 +- .../basics/fail_paren_match_regression.carbon | 7 ++-- .../testdata/basics/function_call.carbon | 1 - toolchain/parser/testdata/class/basic.carbon | 1 - .../testdata/class/fn_definitions.carbon | 1 - toolchain/parser/testdata/class/var.carbon | 1 - .../for/fail_colon_instead_of_in.carbon | 3 +- .../testdata/for/fail_missing_in.carbon | 3 +- .../testdata/for/fail_missing_var.carbon | 3 +- toolchain/parser/testdata/for/nested.carbon | 1 - toolchain/parser/testdata/for/simple.carbon | 1 - .../testdata/function/declaration/addr.carbon | 1 - .../function/declaration/basic.carbon | 1 - .../function/declaration/deduced_empty.carbon | 1 - .../declaration/deduced_params.carbon | 1 - .../fail_identifier_instead_of_sig.carbon | 3 +- .../fail_missing_deduced_close.carbon | 7 ++-- .../declaration/fail_missing_name.carbon | 3 +- .../declaration/fail_no_sig_or_semi.carbon | 3 +- .../declaration/fail_only_fn_and_semi.carbon | 3 +- .../fail_repeated_fn_and_semi.carbon | 3 +- ...skip_indented_newline_until_outdent.carbon | 3 +- ...ail_skip_indented_newline_with_semi.carbon | 3 +- ..._skip_indented_newline_without_semi.carbon | 3 +- .../fail_skip_to_newline_without_semi.carbon | 3 +- .../fail_skip_without_semi_to_curly.carbon | 3 +- .../fail_with_identifier_as_param.carbon | 3 +- ...hout_name_and_many_tokens_in_params.carbon | 3 +- .../function/declaration/params.carbon | 1 - .../declaration/with_return_type.carbon | 1 - .../testdata/function/definition/basic.carbon | 1 - .../fail_identifier_in_statements.carbon | 3 +- .../function/definition/with_params.carbon | 1 - .../definition/with_return_type.carbon | 1 - .../generics/deduced_params/empty.carbon | 1 - .../deduced_params/fail_no_parens.carbon | 9 ++--- .../generics/deduced_params/one.carbon | 1 - .../deduced_params/one_suffix_comma.carbon | 1 - .../generics/deduced_params/six.carbon | 1 - .../generics/deduced_params/two.carbon | 1 - .../deduced_params/two_suffix_comma.carbon | 1 - .../generics/generic_params/basic.carbon | 1 - .../generics/generic_params/template.carbon | 1 - .../generic_params/template_addr.carbon | 1 - .../testdata/generics/interface/basic.carbon | 1 - .../generics/interface/declaration.carbon | 1 - .../generics/interface/empty_body.carbon | 1 - .../interface/fail_missing_name.carbon | 3 +- .../interface/fail_missing_open_curly.carbon | 5 +-- .../interface/fail_no_impl_allowed.carbon | 3 +- .../interface/fail_self_param_syntax.carbon | 5 +-- .../generics/interface/non_instance_fn.carbon | 1 - .../generics/interface/self_pointer.carbon | 1 - .../generics/named_constraint/basic.carbon | 1 - .../fail_no_impl_allowed.carbon | 3 +- .../testdata/generics/params/empty.carbon | 1 - .../testdata/generics/params/one.carbon | 1 - .../generics/params/one_suffix_comma.carbon | 1 - .../testdata/generics/params/six.carbon | 1 - .../testdata/generics/params/two.carbon | 1 - .../generics/params/two_suffix_comma.carbon | 1 - toolchain/parser/testdata/if/basic.carbon | 1 - toolchain/parser/testdata/if/else.carbon | 1 - .../testdata/if/fail_else_unbraced.carbon | 9 ++--- .../parser/testdata/if/fail_errors.carbon | 11 +++--- .../parser/testdata/if/fail_unbraced.carbon | 7 ++-- toolchain/parser/testdata/lit.cfg.py | 1 - .../testdata/operators/associative.carbon | 1 - .../fail_infix_uneven_space_after.carbon | 3 +- .../operators/fail_invalid_infix.carbon | 9 ++--- .../operators/fail_precedence_and_or.carbon | 3 +- .../operators/fail_precedence_or_and.carbon | 3 +- .../fail_precedence_star_minus.carbon | 3 +- .../fail_precedence_star_star.carbon | 3 +- .../operators/fail_star_star_no_space.carbon | 3 +- .../testdata/operators/fail_variety.carbon | 9 ++--- .../testdata/operators/fixity_in_call.carbon | 1 - .../operators/fixity_in_params.carbon | 1 - .../testdata/operators/fixity_in_var.carbon | 1 - .../operators/fixity_with_assign.carbon | 1 - .../parser/testdata/operators/infix.carbon | 1 - .../testdata/operators/infix_no_space.carbon | 1 - .../operators/infix_with_paren_after.carbon | 1 - .../operators/infix_with_paren_before.carbon | 1 - .../operators/missing_precedence_not.carbon | 7 ++-- .../parser/testdata/operators/postfix.carbon | 1 - .../testdata/operators/postfix_repeat.carbon | 1 - .../operators/postfix_space_after_op.carbon | 1 - .../parser/testdata/operators/prefix.carbon | 1 - .../testdata/operators/prefix_no_space.carbon | 1 - .../testdata/operators/prefix_repeat.carbon | 1 - .../recover_infix_uneven_space_before.carbon | 3 +- .../operators/recover_postfix_space.carbon | 3 +- .../recover_postfix_space_before_comma.carbon | 3 +- .../recover_postfix_space_in_call.carbon | 3 +- .../recover_postfix_space_surrounding.carbon | 5 +-- .../operators/recover_prefix_space.carbon | 5 +-- ...ver_prefix_uneven_space_with_assign.carbon | 3 +- toolchain/parser/testdata/package/api.carbon | 1 - .../testdata/package/api_library.carbon | 1 - .../testdata/package/fail_extra_string.carbon | 3 +- .../package/fail_library_is_identifier.carbon | 3 +- .../package/fail_library_skips_name.carbon | 3 +- .../package/fail_name_is_keyword.carbon | 3 +- .../testdata/package/fail_no_name.carbon | 3 +- .../testdata/package/fail_no_semi.carbon | 3 +- .../testdata/package/fail_no_type.carbon | 3 +- .../package/fail_omit_library_keyword.carbon | 3 +- toolchain/parser/testdata/package/impl.carbon | 1 - .../testdata/package/impl_library.carbon | 1 - toolchain/parser/testdata/return/basic.carbon | 1 - toolchain/parser/testdata/return/expr.carbon | 1 - .../testdata/return/fail_expr_no_semi.carbon | 3 +- .../testdata/return/fail_no_semi.carbon | 5 +-- .../testdata/struct/fail_comma_only.carbon | 3 +- .../struct/fail_comma_repeat_in_type.carbon | 3 +- .../struct/fail_comma_repeat_in_value.carbon | 3 +- .../testdata/struct/fail_dot_only.carbon | 3 +- .../struct/fail_dot_string_colon.carbon | 3 +- .../struct/fail_dot_string_equals.carbon | 3 +- .../struct/fail_extra_token_in_type.carbon | 3 +- .../struct/fail_extra_token_in_value.carbon | 3 +- .../struct/fail_identifier_colon.carbon | 3 +- .../struct/fail_identifier_equals.carbon | 3 +- .../struct/fail_identifier_only.carbon | 3 +- .../testdata/struct/fail_missing_type.carbon | 3 +- .../testdata/struct/fail_missing_value.carbon | 3 +- .../struct/fail_mix_type_and_value.carbon | 3 +- .../struct/fail_mix_value_and_type.carbon | 3 +- .../struct/fail_mix_with_unknown.carbon | 9 ++--- .../struct/fail_no_colon_or_equals.carbon | 3 +- .../struct/fail_type_no_designator.carbon | 3 +- .../parser/testdata/struct/no_entries.carbon | 1 - .../testdata/struct/one_entry_no_comma.carbon | 1 - .../struct/one_entry_with_comma.carbon | 1 - .../parser/testdata/struct/two_entries.carbon | 1 - toolchain/parser/testdata/tuple/nested.carbon | 1 - .../parser/testdata/tuple/two_entries.carbon | 1 - .../parser/testdata/var/fail_bad_name.carbon | 3 +- .../parser/testdata/var/fail_empty.carbon | 3 +- toolchain/parser/testdata/var/var.carbon | 1 - toolchain/parser/testdata/while/basic.carbon | 1 - .../parser/testdata/while/fail_no_semi.carbon | 5 +-- .../testdata/while/fail_unbraced.carbon | 3 +- toolchain/semantics/BUILD | 5 +-- toolchain/semantics/semantics_file_test.cpp | 14 ++----- toolchain/semantics/testdata/lit.cfg.py | 1 - 177 files changed, 344 insertions(+), 414 deletions(-) create mode 100644 toolchain/lexer/lexer_file_test.cpp delete mode 100644 toolchain/lexer/testdata/BUILD delete mode 120000 toolchain/lexer/testdata/lit.cfg.py create mode 100644 toolchain/lowering/lowering_file_test.cpp delete mode 100644 toolchain/lowering/testdata/BUILD delete mode 120000 toolchain/lowering/testdata/lit.cfg.py create mode 100644 toolchain/parser/parse_tree_file_test.cpp delete mode 100644 toolchain/parser/testdata/BUILD delete mode 120000 toolchain/parser/testdata/lit.cfg.py delete mode 120000 toolchain/semantics/testdata/lit.cfg.py diff --git a/toolchain/driver/BUILD b/toolchain/driver/BUILD index 00d0924ad80a3..fce89fb4bd1f4 100644 --- a/toolchain/driver/BUILD +++ b/toolchain/driver/BUILD @@ -7,8 +7,6 @@ load("//bazel/fuzzing:rules.bzl", "cc_fuzz_test") package(default_visibility = ["//visibility:public"]) -exports_files(["lit.cfg.py"]) - cc_library( name = "driver", srcs = ["driver.cpp"], diff --git a/toolchain/driver/driver.cpp b/toolchain/driver/driver.cpp index 3a6e598429735..66dfcb2573cae 100644 --- a/toolchain/driver/driver.cpp +++ b/toolchain/driver/driver.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "toolchain/diagnostics/diagnostic_emitter.h" #include "toolchain/diagnostics/sorting_diagnostic_consumer.h" #include "toolchain/lexer/tokenized_buffer.h" #include "toolchain/lowering/lower_to_llvm.h" @@ -40,7 +41,8 @@ auto GetSubcommand(llvm::StringRef name) -> Subcommand { } // namespace auto Driver::RunFullCommand(llvm::ArrayRef args) -> bool { - DiagnosticConsumer* consumer = &ConsoleDiagnosticConsumer(); + StreamDiagnosticConsumer stream_consumer(error_stream_); + DiagnosticConsumer* consumer = &stream_consumer; std::unique_ptr sorting_consumer; // TODO: Figure out a command-line support library, this is temporary. if (!args.empty() && args[0] == "-v") { diff --git a/toolchain/lexer/BUILD b/toolchain/lexer/BUILD index 6d03d70670d46..0c23f7a7a75ea 100644 --- a/toolchain/lexer/BUILD +++ b/toolchain/lexer/BUILD @@ -3,6 +3,8 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception load("//bazel/fuzzing:rules.bzl", "cc_fuzz_test") +load("//bazel/sh_run:rules.bzl", "glob_sh_run") +load("//testing/file_test:rules.bzl", "file_test") package(default_visibility = ["//visibility:public"]) @@ -228,3 +230,25 @@ cc_fuzz_test( "@llvm-project//llvm:Support", ], ) + +file_test( + name = "lexer_file_test", + srcs = ["lexer_file_test.cpp"], + tests = glob(["testdata/**/*.carbon"]), + deps = [ + "//testing/file_test:file_test_base", + "//toolchain/driver", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "dump", + "tokens", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], +) diff --git a/toolchain/lexer/lexer_file_test.cpp b/toolchain/lexer/lexer_file_test.cpp new file mode 100644 index 0000000000000..a57e4e92bee9e --- /dev/null +++ b/toolchain/lexer/lexer_file_test.cpp @@ -0,0 +1,37 @@ +// 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 +#include + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "testing/file_test/file_test_base.h" +#include "toolchain/driver/driver.h" + +namespace Carbon::Testing { +namespace { + +class LexerFileTest : public FileTestBase { + public: + explicit LexerFileTest(llvm::StringRef path) : FileTestBase(path) {} + + void RunOverFile(llvm::raw_ostream& stdout, + llvm::raw_ostream& stderr) override { + Driver driver(stdout, stderr); + driver.RunFullCommand({"dump", "tokens", path()}); + } +}; + +} // namespace + +auto RegisterFileTests(const std::vector& paths) -> void { + LexerFileTest::RegisterTests( + "LexerFileTest", paths, + [](llvm::StringRef path) { return new LexerFileTest(path); }); +} + +} // namespace Carbon::Testing diff --git a/toolchain/lexer/lit_autoupdate.py b/toolchain/lexer/lit_autoupdate.py index a7b053d3ba85a..b026d94afa3a1 100755 --- a/toolchain/lexer/lit_autoupdate.py +++ b/toolchain/lexer/lit_autoupdate.py @@ -36,7 +36,6 @@ def main() -> None: "--line_number_delta_prefix={{ *}}", "--line_number_pattern=" r"(?P line: )(?P *\d+)(?P,)", - "--lit_run=%{carbon-run-tokens}", "--testdata=toolchain/lexer/testdata", ] + sys.argv[1:] os.execv(actual_py, args) diff --git a/toolchain/lexer/testdata/BUILD b/toolchain/lexer/testdata/BUILD deleted file mode 100644 index b74419e865616..0000000000000 --- a/toolchain/lexer/testdata/BUILD +++ /dev/null @@ -1,27 +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 - -load("//bazel/sh_run:rules.bzl", "glob_sh_run") -load("//bazel/testing:lit.bzl", "glob_lit_tests") - -glob_lit_tests( - data = [ - "//bazel/testing:merge_output", - "//toolchain/driver:carbon", - "@llvm-project//llvm:FileCheck", - "@llvm-project//llvm:not", - ], - driver = "lit.cfg.py", - test_file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "dump", - "tokens", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], -) diff --git a/toolchain/lexer/testdata/carbon_test.carbon b/toolchain/lexer/testdata/carbon_test.carbon index ac11c46ece6b9..1572a308decd1 100644 --- a/toolchain/lexer/testdata/carbon_test.carbon +++ b/toolchain/lexer/testdata/carbon_test.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-tokens} // CHECK:STDOUT: [ // CHECK:STDOUT: { index: 0, kind: 'Fn', line: {{ *}}[[@LINE+7]], column: 1, indent: 1, spelling: 'fn', has_trailing_space: true }, diff --git a/toolchain/lexer/testdata/lit.cfg.py b/toolchain/lexer/testdata/lit.cfg.py deleted file mode 120000 index c323f8a5e8da2..0000000000000 --- a/toolchain/lexer/testdata/lit.cfg.py +++ /dev/null @@ -1 +0,0 @@ -../../../bazel/testing/lit.cfg.py \ No newline at end of file diff --git a/toolchain/lowering/BUILD b/toolchain/lowering/BUILD index feb011966ad65..141ae59592a34 100644 --- a/toolchain/lowering/BUILD +++ b/toolchain/lowering/BUILD @@ -2,6 +2,9 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +load("//bazel/sh_run:rules.bzl", "glob_sh_run") +load("//testing/file_test:rules.bzl", "file_test") + package(default_visibility = ["//visibility:public"]) cc_library( @@ -29,3 +32,37 @@ cc_library( "@llvm-project//llvm:Support", ], ) + +file_test( + name = "lowering_file_test", + srcs = ["lowering_file_test.cpp"], + tests = glob(["testdata/**/*.carbon"]), + deps = [ + "//testing/file_test:file_test_base", + "//toolchain/driver", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "dump", + "llvm-ir", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "-v", + "dump", + "llvm-ir", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], + run_ext = "verbose", +) diff --git a/toolchain/lowering/lit_autoupdate.py b/toolchain/lowering/lit_autoupdate.py index 2fa0fb1cdde14..b6cc10c9e8d3f 100755 --- a/toolchain/lowering/lit_autoupdate.py +++ b/toolchain/lowering/lit_autoupdate.py @@ -26,7 +26,6 @@ def main() -> None: "--tool=carbon", "--autoupdate_arg=dump", "--autoupdate_arg=llvm-ir", - "--lit_run=%{carbon-run-lowering}", "--testdata=toolchain/lowering/testdata", ] + sys.argv[1:] os.execv(actual_py, args) diff --git a/toolchain/lowering/lowering_file_test.cpp b/toolchain/lowering/lowering_file_test.cpp new file mode 100644 index 0000000000000..f23ad5b5b93ac --- /dev/null +++ b/toolchain/lowering/lowering_file_test.cpp @@ -0,0 +1,37 @@ +// 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 +#include + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "testing/file_test/file_test_base.h" +#include "toolchain/driver/driver.h" + +namespace Carbon::Testing { +namespace { + +class LoweringFileTest : public FileTestBase { + public: + explicit LoweringFileTest(llvm::StringRef path) : FileTestBase(path) {} + + void RunOverFile(llvm::raw_ostream& stdout, + llvm::raw_ostream& stderr) override { + Driver driver(stdout, stderr); + driver.RunFullCommand({"dump", "llvm-ir", path()}); + } +}; + +} // namespace + +auto RegisterFileTests(const std::vector& paths) -> void { + LoweringFileTest::RegisterTests( + "LoweringFileTest", paths, + [](llvm::StringRef path) { return new LoweringFileTest(path); }); +} + +} // namespace Carbon::Testing diff --git a/toolchain/lowering/testdata/BUILD b/toolchain/lowering/testdata/BUILD deleted file mode 100644 index 1325621af24a2..0000000000000 --- a/toolchain/lowering/testdata/BUILD +++ /dev/null @@ -1,39 +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 - -load("//bazel/sh_run:rules.bzl", "glob_sh_run") -load("//bazel/testing:lit.bzl", "glob_lit_tests") - -glob_lit_tests( - data = [ - "//bazel/testing:merge_output", - "//toolchain/driver:carbon", - "@llvm-project//llvm:FileCheck", - "@llvm-project//llvm:not", - ], - driver = "lit.cfg.py", - test_file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "dump", - "llvm-ir", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "-v", - "dump", - "llvm-ir", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], - run_ext = "verbose", -) diff --git a/toolchain/lowering/testdata/basics/empty.carbon b/toolchain/lowering/testdata/basics/empty.carbon index aa9213f02054d..2e594955c003a 100644 --- a/toolchain/lowering/testdata/basics/empty.carbon +++ b/toolchain/lowering/testdata/basics/empty.carbon @@ -3,6 +3,5 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/basics/empty.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/basics/empty.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/basics/empty.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/basics/empty.carbon" diff --git a/toolchain/lowering/testdata/basics/fail_before_lowering.carbon b/toolchain/lowering/testdata/basics/fail_before_lowering.carbon index 3cba2a64235b6..6adaaf683e535 100644 --- a/toolchain/lowering/testdata/basics/fail_before_lowering.carbon +++ b/toolchain/lowering/testdata/basics/fail_before_lowering.carbon @@ -4,7 +4,6 @@ // // This validates that earlier errors prevent lowering, without crashing. // AUTOUPDATE -// RUN: %{not} %{carbon-run-lowering} -// CHECK:STDERR: {{.*}}/toolchain/lowering/testdata/basics/fail_before_lowering.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. +// CHECK:STDERR: toolchain/lowering/testdata/basics/fail_before_lowering.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. a; diff --git a/toolchain/lowering/testdata/basics/zero.carbon b/toolchain/lowering/testdata/basics/zero.carbon index 186f64c6d6bf8..9f0081a4498f5 100644 --- a/toolchain/lowering/testdata/basics/zero.carbon +++ b/toolchain/lowering/testdata/basics/zero.carbon @@ -3,9 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/basics/zero.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/basics/zero.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/basics/zero.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/basics/zero.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { // CHECK:STDOUT: entry: diff --git a/toolchain/lowering/testdata/function/definition/params_one.carbon b/toolchain/lowering/testdata/function/definition/params_one.carbon index 106a70f7ed4ce..74848b730295c 100644 --- a/toolchain/lowering/testdata/function/definition/params_one.carbon +++ b/toolchain/lowering/testdata/function/definition/params_one.carbon @@ -3,9 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/function/definition/params_one.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/function/definition/params_one.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_one.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_one.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define void @Foo(i32 %a) { // CHECK:STDOUT: entry: diff --git a/toolchain/lowering/testdata/function/definition/params_two.carbon b/toolchain/lowering/testdata/function/definition/params_two.carbon index 3af7b7e1e4303..9b137b9c8dcf0 100644 --- a/toolchain/lowering/testdata/function/definition/params_two.carbon +++ b/toolchain/lowering/testdata/function/definition/params_two.carbon @@ -3,9 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/function/definition/params_two.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/function/definition/params_two.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_two.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_two.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define void @Foo(i32 %a, i32 %b) { // CHECK:STDOUT: entry: diff --git a/toolchain/lowering/testdata/function/definition/params_zero.carbon b/toolchain/lowering/testdata/function/definition/params_zero.carbon index 3de6972bac592..938e08f2e0375 100644 --- a/toolchain/lowering/testdata/function/definition/params_zero.carbon +++ b/toolchain/lowering/testdata/function/definition/params_zero.carbon @@ -3,9 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/function/definition/params_zero.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/function/definition/params_zero.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_zero.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_zero.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define void @Foo() { // CHECK:STDOUT: entry: diff --git a/toolchain/lowering/testdata/lit.cfg.py b/toolchain/lowering/testdata/lit.cfg.py deleted file mode 120000 index c323f8a5e8da2..0000000000000 --- a/toolchain/lowering/testdata/lit.cfg.py +++ /dev/null @@ -1 +0,0 @@ -../../../bazel/testing/lit.cfg.py \ No newline at end of file diff --git a/toolchain/lowering/testdata/return/no_value.carbon b/toolchain/lowering/testdata/return/no_value.carbon index fff9cb9e4e50d..8070351b945fb 100644 --- a/toolchain/lowering/testdata/return/no_value.carbon +++ b/toolchain/lowering/testdata/return/no_value.carbon @@ -3,9 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/return/no_value.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/return/no_value.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/return/no_value.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/return/no_value.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define void @Main() { // CHECK:STDOUT: entry: diff --git a/toolchain/lowering/testdata/return/value.carbon b/toolchain/lowering/testdata/return/value.carbon index a2ce60b9c91ae..acf9ee2cf2c9e 100644 --- a/toolchain/lowering/testdata/return/value.carbon +++ b/toolchain/lowering/testdata/return/value.carbon @@ -3,9 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-lowering} -// CHECK:STDOUT: ; ModuleID = '{{.*}}/toolchain/lowering/testdata/return/value.carbon' -// CHECK:STDOUT: source_filename = "{{.*}}/toolchain/lowering/testdata/return/value.carbon" +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/return/value.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/return/value.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { // CHECK:STDOUT: entry: diff --git a/toolchain/parser/BUILD b/toolchain/parser/BUILD index 3f7b73d2c74a8..e863f87bee7af 100644 --- a/toolchain/parser/BUILD +++ b/toolchain/parser/BUILD @@ -3,6 +3,8 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception load("//bazel/fuzzing:rules.bzl", "cc_fuzz_test") +load("//bazel/sh_run:rules.bzl", "glob_sh_run") +load("//testing/file_test:rules.bzl", "file_test") package(default_visibility = ["//visibility:public"]) @@ -109,3 +111,37 @@ cc_test( "@com_google_googletest//:gtest", ], ) + +file_test( + name = "parse_tree_file_test", + srcs = ["parse_tree_file_test.cpp"], + tests = glob(["testdata/**/*.carbon"]), + deps = [ + "//testing/file_test:file_test_base", + "//toolchain/driver", + "@com_google_googletest//:gtest", + "@llvm-project//llvm:Support", + ], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "dump", + "parse-tree", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], +) + +glob_sh_run( + args = [ + "$(location //toolchain/driver:carbon)", + "-v", + "dump", + "parse-tree", + ], + data = ["//toolchain/driver:carbon"], + file_exts = ["carbon"], + run_ext = "verbose", +) diff --git a/toolchain/parser/lit_autoupdate.py b/toolchain/parser/lit_autoupdate.py index dfe05bf427e87..1d116451fdec6 100755 --- a/toolchain/parser/lit_autoupdate.py +++ b/toolchain/parser/lit_autoupdate.py @@ -26,7 +26,6 @@ def main() -> None: "--tool=carbon", "--autoupdate_arg=dump", "--autoupdate_arg=parse-tree", - "--lit_run=%{carbon-run-parser}", "--testdata=toolchain/parser/testdata", ] + sys.argv[1:] os.execv(actual_py, args) diff --git a/toolchain/parser/parse_tree_file_test.cpp b/toolchain/parser/parse_tree_file_test.cpp new file mode 100644 index 0000000000000..e754299553e4f --- /dev/null +++ b/toolchain/parser/parse_tree_file_test.cpp @@ -0,0 +1,37 @@ +// 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 +#include + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "testing/file_test/file_test_base.h" +#include "toolchain/driver/driver.h" + +namespace Carbon::Testing { +namespace { + +class ParserFileTest : public FileTestBase { + public: + explicit ParserFileTest(llvm::StringRef path) : FileTestBase(path) {} + + void RunOverFile(llvm::raw_ostream& stdout, + llvm::raw_ostream& stderr) override { + Driver driver(stdout, stderr); + driver.RunFullCommand({"dump", "parse-tree", path()}); + } +}; + +} // namespace + +auto RegisterFileTests(const std::vector& paths) -> void { + ParserFileTest::RegisterTests( + "ParserFileTest", paths, + [](llvm::StringRef path) { return new ParserFileTest(path); }); +} + +} // namespace Carbon::Testing diff --git a/toolchain/parser/testdata/BUILD b/toolchain/parser/testdata/BUILD deleted file mode 100644 index 39a9a50c86e01..0000000000000 --- a/toolchain/parser/testdata/BUILD +++ /dev/null @@ -1,39 +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 - -load("//bazel/sh_run:rules.bzl", "glob_sh_run") -load("//bazel/testing:lit.bzl", "glob_lit_tests") - -glob_lit_tests( - data = [ - "//bazel/testing:merge_output", - "//toolchain/driver:carbon", - "@llvm-project//llvm:FileCheck", - "@llvm-project//llvm:not", - ], - driver = "lit.cfg.py", - test_file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "dump", - "parse-tree", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], -) - -glob_sh_run( - args = [ - "$(location //toolchain/driver:carbon)", - "-v", - "dump", - "parse-tree", - ], - data = ["//toolchain/driver:carbon"], - file_exts = ["carbon"], - run_ext = "verbose", -) diff --git a/toolchain/parser/testdata/basics/builtin_types.carbon b/toolchain/parser/testdata/basics/builtin_types.carbon index 8b0134976ab46..5a001da66e68a 100644 --- a/toolchain/parser/testdata/basics/builtin_types.carbon +++ b/toolchain/parser/testdata/basics/builtin_types.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'test_i32'}, diff --git a/toolchain/parser/testdata/basics/empty.carbon b/toolchain/parser/testdata/basics/empty.carbon index e7f134d208a9f..05d24d2b0ad1d 100644 --- a/toolchain/parser/testdata/basics/empty.carbon +++ b/toolchain/parser/testdata/basics/empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parser/testdata/basics/empty_declaration.carbon b/toolchain/parser/testdata/basics/empty_declaration.carbon index d02bc916abad8..d09f6c3fda27a 100644 --- a/toolchain/parser/testdata/basics/empty_declaration.carbon +++ b/toolchain/parser/testdata/basics/empty_declaration.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'EmptyDeclaration', text: ';'}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parser/testdata/basics/fail_invalid_designators.carbon b/toolchain/parser/testdata/basics/fail_invalid_designators.carbon index 34d403c12a714..3b94970ff0fa2 100644 --- a/toolchain/parser/testdata/basics/fail_invalid_designators.carbon +++ b/toolchain/parser/testdata/basics/fail_invalid_designators.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -28,10 +27,10 @@ // NOTE: Move to its own directory when more tests are added. fn F() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. + // CHECK:STDERR: toolchain/parser/testdata/basics/fail_invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. a.; - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. + // CHECK:STDERR: toolchain/parser/testdata/basics/fail_invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. a.fn; - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. + // CHECK:STDERR: toolchain/parser/testdata/basics/fail_invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. a.42; } diff --git a/toolchain/parser/testdata/basics/fail_no_intro_with_semi.carbon b/toolchain/parser/testdata/basics/fail_no_intro_with_semi.carbon index 0c839a308e955..8f36f4ec14a52 100644 --- a/toolchain/parser/testdata/basics/fail_no_intro_with_semi.carbon +++ b/toolchain/parser/testdata/basics/fail_no_intro_with_semi.carbon @@ -3,11 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'EmptyDeclaration', text: ';', has_error: yes}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_no_intro_with_semi.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. +// CHECK:STDERR: toolchain/parser/testdata/basics/fail_no_intro_with_semi.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. foo; diff --git a/toolchain/parser/testdata/basics/fail_no_intro_without_semi.carbon b/toolchain/parser/testdata/basics/fail_no_intro_without_semi.carbon index 90be2682faef8..f1f2041f3cd51 100644 --- a/toolchain/parser/testdata/basics/fail_no_intro_without_semi.carbon +++ b/toolchain/parser/testdata/basics/fail_no_intro_without_semi.carbon @@ -3,11 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'EmptyDeclaration', text: 'foo', has_error: yes}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_no_intro_without_semi.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. +// CHECK:STDERR: toolchain/parser/testdata/basics/fail_no_intro_without_semi.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. foo bar baz diff --git a/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon b/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon index 8bd683f87e00d..393cb37bf8f03 100644 --- a/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon +++ b/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: '=', has_error: yes}, @@ -17,7 +16,7 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon:[[@LINE+3]]:5: Expected pattern in `var` declaration. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon:[[@LINE+2]]:12: Expected `,` or `)`. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/fail_paren_match_regression.carbon:[[@LINE+1]]:15: Expected `;` after expression. +// CHECK:STDERR: toolchain/parser/testdata/basics/fail_paren_match_regression.carbon:[[@LINE+3]]:5: Expected pattern in `var` declaration. +// CHECK:STDERR: toolchain/parser/testdata/basics/fail_paren_match_regression.carbon:[[@LINE+2]]:12: Expected `,` or `)`. +// CHECK:STDERR: toolchain/parser/testdata/basics/fail_paren_match_regression.carbon:[[@LINE+1]]:15: Expected `;` after expression. var = (foo {}) diff --git a/toolchain/parser/testdata/basics/function_call.carbon b/toolchain/parser/testdata/basics/function_call.carbon index 5923998894a32..044d71b26ec0e 100644 --- a/toolchain/parser/testdata/basics/function_call.carbon +++ b/toolchain/parser/testdata/basics/function_call.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/class/basic.carbon b/toolchain/parser/testdata/class/basic.carbon index e1c1723b7e0a8..143d825cbf5ad 100644 --- a/toolchain/parser/testdata/class/basic.carbon +++ b/toolchain/parser/testdata/class/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/class/fn_definitions.carbon b/toolchain/parser/testdata/class/fn_definitions.carbon index 39f3b686bcc77..cfba0c14e61a4 100644 --- a/toolchain/parser/testdata/class/fn_definitions.carbon +++ b/toolchain/parser/testdata/class/fn_definitions.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/class/var.carbon b/toolchain/parser/testdata/class/var.carbon index dcbdf7ac8c916..20132df60ac29 100644 --- a/toolchain/parser/testdata/class/var.carbon +++ b/toolchain/parser/testdata/class/var.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/for/fail_colon_instead_of_in.carbon b/toolchain/parser/testdata/for/fail_colon_instead_of_in.carbon index bac336b3f49f0..b3267f1dd1a94 100644 --- a/toolchain/parser/testdata/for/fail_colon_instead_of_in.carbon +++ b/toolchain/parser/testdata/for/fail_colon_instead_of_in.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, @@ -31,7 +30,7 @@ // CHECK:STDOUT: ] fn foo() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/for/fail_colon_instead_of_in.carbon:[[@LINE+1]]:19: `:` should be replaced by `in`. + // CHECK:STDERR: toolchain/parser/testdata/for/fail_colon_instead_of_in.carbon:[[@LINE+1]]:19: `:` should be replaced by `in`. for (var x: i32 : y) { Print(x); } diff --git a/toolchain/parser/testdata/for/fail_missing_in.carbon b/toolchain/parser/testdata/for/fail_missing_in.carbon index e54ae4db7bb37..df12479eac606 100644 --- a/toolchain/parser/testdata/for/fail_missing_in.carbon +++ b/toolchain/parser/testdata/for/fail_missing_in.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, @@ -31,7 +30,7 @@ // CHECK:STDOUT: ] fn foo() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/for/fail_missing_in.carbon:[[@LINE+1]]:19: Expected `in` after loop `var` declaration. + // CHECK:STDERR: toolchain/parser/testdata/for/fail_missing_in.carbon:[[@LINE+1]]:19: Expected `in` after loop `var` declaration. for (var x: i32 y) { Print(x); } diff --git a/toolchain/parser/testdata/for/fail_missing_var.carbon b/toolchain/parser/testdata/for/fail_missing_var.carbon index ac79359728add..8fdee45daa0bc 100644 --- a/toolchain/parser/testdata/for/fail_missing_var.carbon +++ b/toolchain/parser/testdata/for/fail_missing_var.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, @@ -26,7 +25,7 @@ // CHECK:STDOUT: ] fn foo() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/for/fail_missing_var.carbon:[[@LINE+1]]:8: Expected `var` declaration. + // CHECK:STDERR: toolchain/parser/testdata/for/fail_missing_var.carbon:[[@LINE+1]]:8: Expected `var` declaration. for (x: i32 in y) { Print(x); } diff --git a/toolchain/parser/testdata/for/nested.carbon b/toolchain/parser/testdata/for/nested.carbon index 782a44ffb6ce5..7b3e1e64fc1ae 100644 --- a/toolchain/parser/testdata/for/nested.carbon +++ b/toolchain/parser/testdata/for/nested.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/for/simple.carbon b/toolchain/parser/testdata/for/simple.carbon index 5ed56b3cc6633..185e972a9e7cb 100644 --- a/toolchain/parser/testdata/for/simple.carbon +++ b/toolchain/parser/testdata/for/simple.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/declaration/addr.carbon b/toolchain/parser/testdata/function/declaration/addr.carbon index 8ca84ed9fcd6d..70feb41d505a2 100644 --- a/toolchain/parser/testdata/function/declaration/addr.carbon +++ b/toolchain/parser/testdata/function/declaration/addr.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/declaration/basic.carbon b/toolchain/parser/testdata/function/declaration/basic.carbon index 2a45c474ee0e1..add7d387c34b8 100644 --- a/toolchain/parser/testdata/function/declaration/basic.carbon +++ b/toolchain/parser/testdata/function/declaration/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/function/declaration/deduced_empty.carbon b/toolchain/parser/testdata/function/declaration/deduced_empty.carbon index 91b161775a6df..491e4a9741f89 100644 --- a/toolchain/parser/testdata/function/declaration/deduced_empty.carbon +++ b/toolchain/parser/testdata/function/declaration/deduced_empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/declaration/deduced_params.carbon b/toolchain/parser/testdata/function/declaration/deduced_params.carbon index df9726332fb1d..a95ca6309fab8 100644 --- a/toolchain/parser/testdata/function/declaration/deduced_params.carbon +++ b/toolchain/parser/testdata/function/declaration/deduced_params.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/declaration/fail_identifier_instead_of_sig.carbon b/toolchain/parser/testdata/function/declaration/fail_identifier_instead_of_sig.carbon index 9d8a737e384ff..99b273b0c5b42 100644 --- a/toolchain/parser/testdata/function/declaration/fail_identifier_instead_of_sig.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_identifier_instead_of_sig.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, @@ -11,5 +10,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_identifier_instead_of_sig.carbon:[[@LINE+1]]:8: `fn` requires a `(` for parameters. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_identifier_instead_of_sig.carbon:[[@LINE+1]]:8: `fn` requires a `(` for parameters. fn foo bar; diff --git a/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon b/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon index 9b8ad08822d00..5b2dfae3a74e0 100644 --- a/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Div'}, @@ -17,7 +16,7 @@ // CHECK:STDOUT: ] // Fix and uncomment this to test error handling. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+2]]:7: Closing symbol does not match most recent opening symbol. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+1]]:8: Expected parameter declaration. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+2]]:7: Closing symbol does not match most recent opening symbol. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+1]]:8: Expected parameter declaration. fn Div[(); -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+0]]:181: A `(` for parameters is required after deduced parameters. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_missing_deduced_close.carbon:[[@LINE+0]]:174: A `(` for parameters is required after deduced parameters. diff --git a/toolchain/parser/testdata/function/declaration/fail_missing_name.carbon b/toolchain/parser/testdata/function/declaration/fail_missing_name.carbon index 63b4acb8f3c69..7a5c95ba3de8c 100644 --- a/toolchain/parser/testdata/function/declaration/fail_missing_name.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_missing_name.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_missing_name.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_missing_name.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. fn (); diff --git a/toolchain/parser/testdata/function/declaration/fail_no_sig_or_semi.carbon b/toolchain/parser/testdata/function/declaration/fail_no_sig_or_semi.carbon index 42ef84ce45a68..ad0fc20ddf0f8 100644 --- a/toolchain/parser/testdata/function/declaration/fail_no_sig_or_semi.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_no_sig_or_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, @@ -11,5 +10,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_no_sig_or_semi.carbon:[[@LINE+1]]:7: `fn` requires a `(` for parameters. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_no_sig_or_semi.carbon:[[@LINE+1]]:7: `fn` requires a `(` for parameters. fn foo diff --git a/toolchain/parser/testdata/function/declaration/fail_only_fn_and_semi.carbon b/toolchain/parser/testdata/function/declaration/fail_only_fn_and_semi.carbon index 8fef102a185ec..589592765a4cd 100644 --- a/toolchain/parser/testdata/function/declaration/fail_only_fn_and_semi.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_only_fn_and_semi.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_only_fn_and_semi.carbon:[[@LINE+1]]:3: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_only_fn_and_semi.carbon:[[@LINE+1]]:3: `fn` introducer should be followed by a name. fn; diff --git a/toolchain/parser/testdata/function/declaration/fail_repeated_fn_and_semi.carbon b/toolchain/parser/testdata/function/declaration/fail_repeated_fn_and_semi.carbon index 980c19bcfa28a..aee502fca0eb7 100644 --- a/toolchain/parser/testdata/function/declaration/fail_repeated_fn_and_semi.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_repeated_fn_and_semi.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_repeated_fn_and_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_repeated_fn_and_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. fn fn; diff --git a/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon b/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon index 8daaf1f63d18d..524740f22fbb1 100644 --- a/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2}, @@ -15,7 +14,7 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon:[[@LINE+1]]:6: `fn` introducer should be followed by a name. + // CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_until_outdent.carbon:[[@LINE+1]]:6: `fn` introducer should be followed by a name. fn (x, y, z) diff --git a/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_with_semi.carbon b/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_with_semi.carbon index dd60e4e805885..6e364daa9a221 100644 --- a/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_with_semi.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_with_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', has_error: yes, subtree_size: 2}, @@ -15,7 +14,7 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_with_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_with_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. fn (x, y, z); diff --git a/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon b/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon index 8acf7cb3a3104..5cfaefedcccfa 100644 --- a/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2}, @@ -15,7 +14,7 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_skip_indented_newline_without_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. fn (x, y, z) diff --git a/toolchain/parser/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon b/toolchain/parser/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon index f0695b501abe6..3e9ee853e2bd3 100644 --- a/toolchain/parser/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2}, @@ -15,6 +14,6 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_skip_to_newline_without_semi.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. fn () fn F(); diff --git a/toolchain/parser/testdata/function/declaration/fail_skip_without_semi_to_curly.carbon b/toolchain/parser/testdata/function/declaration/fail_skip_without_semi_to_curly.carbon index f758f7ab9e6a5..4768473ca7dde 100644 --- a/toolchain/parser/testdata/function/declaration/fail_skip_without_semi_to_curly.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_skip_without_semi_to_curly.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'EmptyDeclaration', text: 'struct', has_error: yes}, // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, @@ -14,6 +13,6 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_skip_without_semi_to_curly.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_skip_without_semi_to_curly.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. struct X { fn () } fn F(); diff --git a/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon b/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon index 3fcd7cba89eec..cff7b9b889cb9 100644 --- a/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, @@ -16,5 +15,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon:[[@LINE+1]]:11: Expected parameter declaration. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_with_identifier_as_param.carbon:[[@LINE+1]]:11: Expected parameter declaration. fn foo(bar); diff --git a/toolchain/parser/testdata/function/declaration/fail_without_name_and_many_tokens_in_params.carbon b/toolchain/parser/testdata/function/declaration/fail_without_name_and_many_tokens_in_params.carbon index cf37928151031..3ed38586e2806 100644 --- a/toolchain/parser/testdata/function/declaration/fail_without_name_and_many_tokens_in_params.carbon +++ b/toolchain/parser/testdata/function/declaration/fail_without_name_and_many_tokens_in_params.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/fail_without_name_and_many_tokens_in_params.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/function/declaration/fail_without_name_and_many_tokens_in_params.carbon:[[@LINE+1]]:4: `fn` introducer should be followed by a name. fn (a tokens c d e f g h i j k l m n o p q r s t u v w x y z); diff --git a/toolchain/parser/testdata/function/declaration/params.carbon b/toolchain/parser/testdata/function/declaration/params.carbon index 7cc94041f0754..34d24f65620c3 100644 --- a/toolchain/parser/testdata/function/declaration/params.carbon +++ b/toolchain/parser/testdata/function/declaration/params.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/declaration/with_return_type.carbon b/toolchain/parser/testdata/function/declaration/with_return_type.carbon index 0943d39781767..352b6a4231a68 100644 --- a/toolchain/parser/testdata/function/declaration/with_return_type.carbon +++ b/toolchain/parser/testdata/function/declaration/with_return_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/definition/basic.carbon b/toolchain/parser/testdata/function/definition/basic.carbon index ebf083b04abb0..4bb28995c7511 100644 --- a/toolchain/parser/testdata/function/definition/basic.carbon +++ b/toolchain/parser/testdata/function/definition/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/function/definition/fail_identifier_in_statements.carbon b/toolchain/parser/testdata/function/definition/fail_identifier_in_statements.carbon index fa0ac977fdafe..40c1594917d04 100644 --- a/toolchain/parser/testdata/function/definition/fail_identifier_in_statements.carbon +++ b/toolchain/parser/testdata/function/definition/fail_identifier_in_statements.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -19,5 +18,5 @@ fn F() { // Note: this might become valid depending on the expression syntax. This test // shouldn't be taken as a sign it should remain invalid. bar -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/definition/fail_identifier_in_statements.carbon:[[@LINE+1]]:1: Expected `;` after expression. +// CHECK:STDERR: toolchain/parser/testdata/function/definition/fail_identifier_in_statements.carbon:[[@LINE+1]]:1: Expected `;` after expression. } diff --git a/toolchain/parser/testdata/function/definition/with_params.carbon b/toolchain/parser/testdata/function/definition/with_params.carbon index 564242da729a4..be27a62046238 100644 --- a/toolchain/parser/testdata/function/definition/with_params.carbon +++ b/toolchain/parser/testdata/function/definition/with_params.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/function/definition/with_return_type.carbon b/toolchain/parser/testdata/function/definition/with_return_type.carbon index d847e45d2b106..256c18ec0a6f4 100644 --- a/toolchain/parser/testdata/function/definition/with_return_type.carbon +++ b/toolchain/parser/testdata/function/definition/with_return_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/generics/deduced_params/empty.carbon b/toolchain/parser/testdata/generics/deduced_params/empty.carbon index 177b8827d6500..1d9ff3a1e520b 100644 --- a/toolchain/parser/testdata/generics/deduced_params/empty.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon b/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon index 7534ec55039a2..b6a776ba77387 100644 --- a/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, @@ -34,14 +33,14 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:12: A `(` for parameters is required after deduced parameters. +// CHECK:STDERR: toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:12: A `(` for parameters is required after deduced parameters. class Foo[]; -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:18: A `(` for parameters is required after deduced parameters. +// CHECK:STDERR: toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:18: A `(` for parameters is required after deduced parameters. class Foo[a: i32]; -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:17: A `(` for parameters is required after deduced parameters. +// CHECK:STDERR: toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:17: A `(` for parameters is required after deduced parameters. interface Bar[] {} -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:23: A `(` for parameters is required after deduced parameters. +// CHECK:STDERR: toolchain/parser/testdata/generics/deduced_params/fail_no_parens.carbon:[[@LINE+1]]:23: A `(` for parameters is required after deduced parameters. interface Bar[a: i32] {} diff --git a/toolchain/parser/testdata/generics/deduced_params/one.carbon b/toolchain/parser/testdata/generics/deduced_params/one.carbon index 653efc8076183..0f008ce7983b4 100644 --- a/toolchain/parser/testdata/generics/deduced_params/one.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/one.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/deduced_params/one_suffix_comma.carbon b/toolchain/parser/testdata/generics/deduced_params/one_suffix_comma.carbon index 5f4951cca6276..5b251340be2e4 100644 --- a/toolchain/parser/testdata/generics/deduced_params/one_suffix_comma.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/one_suffix_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/deduced_params/six.carbon b/toolchain/parser/testdata/generics/deduced_params/six.carbon index 0c555efc80005..7234218fb60dc 100644 --- a/toolchain/parser/testdata/generics/deduced_params/six.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/six.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/deduced_params/two.carbon b/toolchain/parser/testdata/generics/deduced_params/two.carbon index beaf9b21343f6..d02c5c12e66e2 100644 --- a/toolchain/parser/testdata/generics/deduced_params/two.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/two.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/deduced_params/two_suffix_comma.carbon b/toolchain/parser/testdata/generics/deduced_params/two_suffix_comma.carbon index f70c0daf9648e..474ff259ac153 100644 --- a/toolchain/parser/testdata/generics/deduced_params/two_suffix_comma.carbon +++ b/toolchain/parser/testdata/generics/deduced_params/two_suffix_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/generic_params/basic.carbon b/toolchain/parser/testdata/generics/generic_params/basic.carbon index 6fb96eec546bb..e75c76a87a080 100644 --- a/toolchain/parser/testdata/generics/generic_params/basic.carbon +++ b/toolchain/parser/testdata/generics/generic_params/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/generics/generic_params/template.carbon b/toolchain/parser/testdata/generics/generic_params/template.carbon index de233330b7f29..3c40534a4b602 100644 --- a/toolchain/parser/testdata/generics/generic_params/template.carbon +++ b/toolchain/parser/testdata/generics/generic_params/template.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/generics/generic_params/template_addr.carbon b/toolchain/parser/testdata/generics/generic_params/template_addr.carbon index bdf5258a4eaa7..9daa7038ac009 100644 --- a/toolchain/parser/testdata/generics/generic_params/template_addr.carbon +++ b/toolchain/parser/testdata/generics/generic_params/template_addr.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'}, diff --git a/toolchain/parser/testdata/generics/interface/basic.carbon b/toolchain/parser/testdata/generics/interface/basic.carbon index 2e8a947e76f96..e829bf0bf378c 100644 --- a/toolchain/parser/testdata/generics/interface/basic.carbon +++ b/toolchain/parser/testdata/generics/interface/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/interface/declaration.carbon b/toolchain/parser/testdata/generics/interface/declaration.carbon index f8f405f2f672e..2e18fe6c8a588 100644 --- a/toolchain/parser/testdata/generics/interface/declaration.carbon +++ b/toolchain/parser/testdata/generics/interface/declaration.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/interface/empty_body.carbon b/toolchain/parser/testdata/generics/interface/empty_body.carbon index 4a5871af403e2..9a4cfebafcdb4 100644 --- a/toolchain/parser/testdata/generics/interface/empty_body.carbon +++ b/toolchain/parser/testdata/generics/interface/empty_body.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/interface/fail_missing_name.carbon b/toolchain/parser/testdata/generics/interface/fail_missing_name.carbon index f1d680181b4ed..26189e15fb4df 100644 --- a/toolchain/parser/testdata/generics/interface/fail_missing_name.carbon +++ b/toolchain/parser/testdata/generics/interface/fail_missing_name.carbon @@ -3,13 +3,12 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'InterfaceDeclaration', text: 'interface', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_missing_name.carbon:[[@LINE+1]]:11: `interface` introducer should be followed by a name. +// CHECK:STDERR: toolchain/parser/testdata/generics/interface/fail_missing_name.carbon:[[@LINE+1]]:11: `interface` introducer should be followed by a name. interface { } diff --git a/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon b/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon index 5014248967d3c..730d64c84eb14 100644 --- a/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon +++ b/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Bar'}, @@ -14,8 +13,8 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon:[[@LINE+1]]:15: `interface` should either end with a `;` for a declaration or have a `{ ... }` block for a definition. +// CHECK:STDERR: toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon:[[@LINE+1]]:15: `interface` should either end with a `;` for a declaration or have a `{ ... }` block for a definition. interface Bar Baz {} -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon:[[@LINE+1]]:14: `interface` should either end with a `;` for a declaration or have a `{ ... }` block for a definition. +// CHECK:STDERR: toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon:[[@LINE+1]]:14: `interface` should either end with a `;` for a declaration or have a `{ ... }` block for a definition. interface Foo diff --git a/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon b/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon index 4e4996ff301f3..fa4b8960a0558 100644 --- a/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon +++ b/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, @@ -28,7 +27,7 @@ // CHECK:STDOUT: ] interface Foo { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon:[[@LINE+1]]:39: Method implementations are not allowed in interfaces. + // CHECK:STDERR: toolchain/parser/testdata/generics/interface/fail_no_impl_allowed.carbon:[[@LINE+1]]:39: Method implementations are not allowed in interfaces. fn Add[self: Self](b: Self) -> Self { print("You can't do that."); } diff --git a/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon b/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon index 0acbcf47dadcc..adcce72bc1240 100644 --- a/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon +++ b/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, @@ -43,9 +42,9 @@ // CHECK:STDOUT: ] interface Foo { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:13: Expected parameter declaration. + // CHECK:STDERR: toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:13: Expected parameter declaration. fn Sub[me Self](b: Self) -> Self; - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:10: Expected parameter declaration. + // CHECK:STDERR: toolchain/parser/testdata/generics/interface/fail_self_param_syntax.carbon:[[@LINE+1]]:10: Expected parameter declaration. fn Mul[Self](b: Self) -> Self; } diff --git a/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon b/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon index c578988539580..3408985eb6cec 100644 --- a/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon +++ b/toolchain/parser/testdata/generics/interface/non_instance_fn.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/interface/self_pointer.carbon b/toolchain/parser/testdata/generics/interface/self_pointer.carbon index e1c6b882fd449..94322f7a95451 100644 --- a/toolchain/parser/testdata/generics/interface/self_pointer.carbon +++ b/toolchain/parser/testdata/generics/interface/self_pointer.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/named_constraint/basic.carbon b/toolchain/parser/testdata/generics/named_constraint/basic.carbon index 86db57d0b3569..1a179bf6ffbfb 100644 --- a/toolchain/parser/testdata/generics/named_constraint/basic.carbon +++ b/toolchain/parser/testdata/generics/named_constraint/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'NamedConstraintIntroducer', text: 'constraint'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/named_constraint/fail_no_impl_allowed.carbon b/toolchain/parser/testdata/generics/named_constraint/fail_no_impl_allowed.carbon index 0cfc7f5a0f702..83173b0332a95 100644 --- a/toolchain/parser/testdata/generics/named_constraint/fail_no_impl_allowed.carbon +++ b/toolchain/parser/testdata/generics/named_constraint/fail_no_impl_allowed.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'NamedConstraintIntroducer', text: 'constraint'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, @@ -28,6 +27,6 @@ // CHECK:STDOUT: ] constraint Foo { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/named_constraint/fail_no_impl_allowed.carbon:[[@LINE+1]]:39: Method implementations are not allowed in interfaces. + // CHECK:STDERR: toolchain/parser/testdata/generics/named_constraint/fail_no_impl_allowed.carbon:[[@LINE+1]]:39: Method implementations are not allowed in interfaces. fn Add[self: Self](b: Self) -> Self {} } diff --git a/toolchain/parser/testdata/generics/params/empty.carbon b/toolchain/parser/testdata/generics/params/empty.carbon index 28fac6a361a2e..bf6e903d06533 100644 --- a/toolchain/parser/testdata/generics/params/empty.carbon +++ b/toolchain/parser/testdata/generics/params/empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/params/one.carbon b/toolchain/parser/testdata/generics/params/one.carbon index df707855567f7..ddd722182c62e 100644 --- a/toolchain/parser/testdata/generics/params/one.carbon +++ b/toolchain/parser/testdata/generics/params/one.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/params/one_suffix_comma.carbon b/toolchain/parser/testdata/generics/params/one_suffix_comma.carbon index 4673ea28bfdec..90cc9a00b6690 100644 --- a/toolchain/parser/testdata/generics/params/one_suffix_comma.carbon +++ b/toolchain/parser/testdata/generics/params/one_suffix_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/params/six.carbon b/toolchain/parser/testdata/generics/params/six.carbon index e2741420cafcb..4da99a018f436 100644 --- a/toolchain/parser/testdata/generics/params/six.carbon +++ b/toolchain/parser/testdata/generics/params/six.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/params/two.carbon b/toolchain/parser/testdata/generics/params/two.carbon index 35f020bf5f5c8..b3fbf0a79aeed 100644 --- a/toolchain/parser/testdata/generics/params/two.carbon +++ b/toolchain/parser/testdata/generics/params/two.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/generics/params/two_suffix_comma.carbon b/toolchain/parser/testdata/generics/params/two_suffix_comma.carbon index db229bd65030c..cfc608bc7ad5c 100644 --- a/toolchain/parser/testdata/generics/params/two_suffix_comma.carbon +++ b/toolchain/parser/testdata/generics/params/two_suffix_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, diff --git a/toolchain/parser/testdata/if/basic.carbon b/toolchain/parser/testdata/if/basic.carbon index 840e7fd663f7d..332f651b55251 100644 --- a/toolchain/parser/testdata/if/basic.carbon +++ b/toolchain/parser/testdata/if/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/if/else.carbon b/toolchain/parser/testdata/if/else.carbon index 4025e02c17e01..0223a1b452778 100644 --- a/toolchain/parser/testdata/if/else.carbon +++ b/toolchain/parser/testdata/if/else.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/if/fail_else_unbraced.carbon b/toolchain/parser/testdata/if/fail_else_unbraced.carbon index 412d75a460477..c2c6496362727 100644 --- a/toolchain/parser/testdata/if/fail_else_unbraced.carbon +++ b/toolchain/parser/testdata/if/fail_else_unbraced.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -62,15 +61,15 @@ fn F() { if (a) - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. if (b) - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. c; else - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. d; else - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_else_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. e; if (x) { f; } else if (x) { g; } diff --git a/toolchain/parser/testdata/if/fail_errors.carbon b/toolchain/parser/testdata/if/fail_errors.carbon index 1c797ad2c3289..189d31db01a01 100644 --- a/toolchain/parser/testdata/if/fail_errors.carbon +++ b/toolchain/parser/testdata/if/fail_errors.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -40,13 +39,13 @@ // CHECK:STDOUT: ] fn F() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:6: Expected `(` after `if`. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:6: Expected `(` after `if`. if a {} - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:7: Expected expression. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:7: Expected expression. if () {} - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:9: Unexpected tokens before `)`. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:9: Unexpected tokens before `)`. if (b c) {} if (d) -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+2]]:1: Expected braced code block. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:1: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+2]]:1: Expected braced code block. +// CHECK:STDERR: toolchain/parser/testdata/if/fail_errors.carbon:[[@LINE+1]]:1: Expected expression. } diff --git a/toolchain/parser/testdata/if/fail_unbraced.carbon b/toolchain/parser/testdata/if/fail_unbraced.carbon index 97dee8b9e5da9..d3c8ffc0d7d7e 100644 --- a/toolchain/parser/testdata/if/fail_unbraced.carbon +++ b/toolchain/parser/testdata/if/fail_unbraced.carbon @@ -4,7 +4,6 @@ // // TODO: This should have an error. // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -37,10 +36,10 @@ fn F() { if (a) - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. if (b) - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. if (c) - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/fail_unbraced.carbon:[[@LINE+1]]:9: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/if/fail_unbraced.carbon:[[@LINE+1]]:9: Expected braced code block. d; } diff --git a/toolchain/parser/testdata/lit.cfg.py b/toolchain/parser/testdata/lit.cfg.py deleted file mode 120000 index c323f8a5e8da2..0000000000000 --- a/toolchain/parser/testdata/lit.cfg.py +++ /dev/null @@ -1 +0,0 @@ -../../../bazel/testing/lit.cfg.py \ No newline at end of file diff --git a/toolchain/parser/testdata/operators/associative.carbon b/toolchain/parser/testdata/operators/associative.carbon index e5b31a29fd066..ff44d4e5ef796 100644 --- a/toolchain/parser/testdata/operators/associative.carbon +++ b/toolchain/parser/testdata/operators/associative.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/fail_infix_uneven_space_after.carbon b/toolchain/parser/testdata/operators/fail_infix_uneven_space_after.carbon index ef68ea0f473f3..09ef8b4a89c24 100644 --- a/toolchain/parser/testdata/operators/fail_infix_uneven_space_after.carbon +++ b/toolchain/parser/testdata/operators/fail_infix_uneven_space_after.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -18,5 +17,5 @@ // TODO: We could figure out that this first Failed example is infix // with one-token lookahead. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_infix_uneven_space_after.carbon:[[@LINE+1]]:16: Expected `;` after expression. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_infix_uneven_space_after.carbon:[[@LINE+1]]:16: Expected `;` after expression. var n: i8 = n* n; diff --git a/toolchain/parser/testdata/operators/fail_invalid_infix.carbon b/toolchain/parser/testdata/operators/fail_invalid_infix.carbon index 918b0af27adac..5f9fbdacdcc04 100644 --- a/toolchain/parser/testdata/operators/fail_invalid_infix.carbon +++ b/toolchain/parser/testdata/operators/fail_invalid_infix.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'}, @@ -35,10 +34,10 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+1]]:19: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+1]]:19: Expected expression. var a: i32 = n == ; -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+1]]:14: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+1]]:14: Expected expression. var b: i32 = == n; -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+2]]:14: Expected expression. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+1]]:17: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+2]]:14: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_invalid_infix.carbon:[[@LINE+1]]:17: Expected expression. var c: i32 = == ; diff --git a/toolchain/parser/testdata/operators/fail_precedence_and_or.carbon b/toolchain/parser/testdata/operators/fail_precedence_and_or.carbon index 4bd3dc66054de..cebeb7aa57d7b 100644 --- a/toolchain/parser/testdata/operators/fail_precedence_and_or.carbon +++ b/toolchain/parser/testdata/operators/fail_precedence_and_or.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -21,6 +20,6 @@ // CHECK:STDOUT: ] fn F() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_precedence_and_or.carbon:[[@LINE+1]]:11: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: toolchain/parser/testdata/operators/fail_precedence_and_or.carbon:[[@LINE+1]]:11: Parentheses are required to disambiguate operator precedence. a and b or c; } diff --git a/toolchain/parser/testdata/operators/fail_precedence_or_and.carbon b/toolchain/parser/testdata/operators/fail_precedence_or_and.carbon index 494e248963040..02b9fba4325d9 100644 --- a/toolchain/parser/testdata/operators/fail_precedence_or_and.carbon +++ b/toolchain/parser/testdata/operators/fail_precedence_or_and.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -21,6 +20,6 @@ // CHECK:STDOUT: ] fn F() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_precedence_or_and.carbon:[[@LINE+1]]:10: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: toolchain/parser/testdata/operators/fail_precedence_or_and.carbon:[[@LINE+1]]:10: Parentheses are required to disambiguate operator precedence. a or b and c; } diff --git a/toolchain/parser/testdata/operators/fail_precedence_star_minus.carbon b/toolchain/parser/testdata/operators/fail_precedence_star_minus.carbon index 687a26593a1ea..01f983a60b1c3 100644 --- a/toolchain/parser/testdata/operators/fail_precedence_star_minus.carbon +++ b/toolchain/parser/testdata/operators/fail_precedence_star_minus.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -18,5 +17,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_precedence_star_minus.carbon:[[@LINE+1]]:16: Parentheses are required to disambiguate operator precedence. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_precedence_star_minus.carbon:[[@LINE+1]]:16: Parentheses are required to disambiguate operator precedence. var n: i8 = n* -n; diff --git a/toolchain/parser/testdata/operators/fail_precedence_star_star.carbon b/toolchain/parser/testdata/operators/fail_precedence_star_star.carbon index b47200927ba4f..5f9fdf9ef0435 100644 --- a/toolchain/parser/testdata/operators/fail_precedence_star_star.carbon +++ b/toolchain/parser/testdata/operators/fail_precedence_star_star.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -18,5 +17,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_precedence_star_star.carbon:[[@LINE+1]]:16: Parentheses are required to disambiguate operator precedence. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_precedence_star_star.carbon:[[@LINE+1]]:16: Parentheses are required to disambiguate operator precedence. var n: i8 = n* *p; diff --git a/toolchain/parser/testdata/operators/fail_star_star_no_space.carbon b/toolchain/parser/testdata/operators/fail_star_star_no_space.carbon index c17042dac4f53..b3b86eec072dc 100644 --- a/toolchain/parser/testdata/operators/fail_star_star_no_space.carbon +++ b/toolchain/parser/testdata/operators/fail_star_star_no_space.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -21,5 +20,5 @@ // before we notice the missing whitespace around the second `*`. // It'd be better to (somehow) form n*(*p) and reject due to the missing // whitespace around the first `*`. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_star_star_no_space.carbon:[[@LINE+1]]:16: Expected `;` after expression. +// CHECK:STDERR: toolchain/parser/testdata/operators/fail_star_star_no_space.carbon:[[@LINE+1]]:16: Expected `;` after expression. var n: i8 = n**p; diff --git a/toolchain/parser/testdata/operators/fail_variety.carbon b/toolchain/parser/testdata/operators/fail_variety.carbon index 5b6ea6e92a21b..82d8ac55876a6 100644 --- a/toolchain/parser/testdata/operators/fail_variety.carbon +++ b/toolchain/parser/testdata/operators/fail_variety.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -36,9 +35,9 @@ // CHECK:STDOUT: ] fn F() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+4]]:29: Parentheses are required to disambiguate operator precedence. - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+3]]:34: Parentheses are required to disambiguate operator precedence. - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+2]]:38: Parentheses are required to disambiguate operator precedence. - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+1]]:40: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+4]]:29: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+3]]:34: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+2]]:38: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: toolchain/parser/testdata/operators/fail_variety.carbon:[[@LINE+1]]:40: Parentheses are required to disambiguate operator precedence. n = a * b + c * d = d * d << e & f - not g; } diff --git a/toolchain/parser/testdata/operators/fixity_in_call.carbon b/toolchain/parser/testdata/operators/fixity_in_call.carbon index 996514da2f980..5804f20d45c9d 100644 --- a/toolchain/parser/testdata/operators/fixity_in_call.carbon +++ b/toolchain/parser/testdata/operators/fixity_in_call.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/fixity_in_params.carbon b/toolchain/parser/testdata/operators/fixity_in_params.carbon index 80814d1ecc8b9..6762a7740bb23 100644 --- a/toolchain/parser/testdata/operators/fixity_in_params.carbon +++ b/toolchain/parser/testdata/operators/fixity_in_params.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/fixity_in_var.carbon b/toolchain/parser/testdata/operators/fixity_in_var.carbon index b54ea4b85b9ba..b15d233ed6e73 100644 --- a/toolchain/parser/testdata/operators/fixity_in_var.carbon +++ b/toolchain/parser/testdata/operators/fixity_in_var.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/fixity_with_assign.carbon b/toolchain/parser/testdata/operators/fixity_with_assign.carbon index 23a8589652645..1fed453a97c29 100644 --- a/toolchain/parser/testdata/operators/fixity_with_assign.carbon +++ b/toolchain/parser/testdata/operators/fixity_with_assign.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/infix.carbon b/toolchain/parser/testdata/operators/infix.carbon index c7c5a17cfe0a1..ab320d2a9a17b 100644 --- a/toolchain/parser/testdata/operators/infix.carbon +++ b/toolchain/parser/testdata/operators/infix.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, diff --git a/toolchain/parser/testdata/operators/infix_no_space.carbon b/toolchain/parser/testdata/operators/infix_no_space.carbon index cbc897f3791ae..5677bd53665bd 100644 --- a/toolchain/parser/testdata/operators/infix_no_space.carbon +++ b/toolchain/parser/testdata/operators/infix_no_space.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, diff --git a/toolchain/parser/testdata/operators/infix_with_paren_after.carbon b/toolchain/parser/testdata/operators/infix_with_paren_after.carbon index dd38fd7a72406..c6934558fd729 100644 --- a/toolchain/parser/testdata/operators/infix_with_paren_after.carbon +++ b/toolchain/parser/testdata/operators/infix_with_paren_after.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, diff --git a/toolchain/parser/testdata/operators/infix_with_paren_before.carbon b/toolchain/parser/testdata/operators/infix_with_paren_before.carbon index 9b6eb4cdc9969..a47b3e12d9e6d 100644 --- a/toolchain/parser/testdata/operators/infix_with_paren_before.carbon +++ b/toolchain/parser/testdata/operators/infix_with_paren_before.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, diff --git a/toolchain/parser/testdata/operators/missing_precedence_not.carbon b/toolchain/parser/testdata/operators/missing_precedence_not.carbon index 1bfaaa6174773..419d3dd922e84 100644 --- a/toolchain/parser/testdata/operators/missing_precedence_not.carbon +++ b/toolchain/parser/testdata/operators/missing_precedence_not.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -24,8 +23,8 @@ // CHECK:STDOUT: ] fn F() { - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/missing_precedence_not.carbon:[[@LINE+3]]:3: Whitespace is required before this unary operator. - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/missing_precedence_not.carbon:[[@LINE+2]]:13: Whitespace is required before this unary operator. - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/missing_precedence_not.carbon:[[@LINE+1]]:23: Whitespace is required before this unary operator. + // CHECK:STDERR: toolchain/parser/testdata/operators/missing_precedence_not.carbon:[[@LINE+3]]:3: Whitespace is required before this unary operator. + // CHECK:STDERR: toolchain/parser/testdata/operators/missing_precedence_not.carbon:[[@LINE+2]]:13: Whitespace is required before this unary operator. + // CHECK:STDERR: toolchain/parser/testdata/operators/missing_precedence_not.carbon:[[@LINE+1]]:23: Whitespace is required before this unary operator. not a and not b and not c; } diff --git a/toolchain/parser/testdata/operators/postfix.carbon b/toolchain/parser/testdata/operators/postfix.carbon index 5e8c58d1ac9c0..79fed10462bae 100644 --- a/toolchain/parser/testdata/operators/postfix.carbon +++ b/toolchain/parser/testdata/operators/postfix.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'v'}, diff --git a/toolchain/parser/testdata/operators/postfix_repeat.carbon b/toolchain/parser/testdata/operators/postfix_repeat.carbon index 32e182a9586cc..127eb69e1c5b0 100644 --- a/toolchain/parser/testdata/operators/postfix_repeat.carbon +++ b/toolchain/parser/testdata/operators/postfix_repeat.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/postfix_space_after_op.carbon b/toolchain/parser/testdata/operators/postfix_space_after_op.carbon index 4e797f2d5b791..0b18ceb8aea5c 100644 --- a/toolchain/parser/testdata/operators/postfix_space_after_op.carbon +++ b/toolchain/parser/testdata/operators/postfix_space_after_op.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'v'}, diff --git a/toolchain/parser/testdata/operators/prefix.carbon b/toolchain/parser/testdata/operators/prefix.carbon index b70d5ad839c66..f263a3d2af7e2 100644 --- a/toolchain/parser/testdata/operators/prefix.carbon +++ b/toolchain/parser/testdata/operators/prefix.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, diff --git a/toolchain/parser/testdata/operators/prefix_no_space.carbon b/toolchain/parser/testdata/operators/prefix_no_space.carbon index d6a0eaf754b25..de0a62f1fb204 100644 --- a/toolchain/parser/testdata/operators/prefix_no_space.carbon +++ b/toolchain/parser/testdata/operators/prefix_no_space.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, diff --git a/toolchain/parser/testdata/operators/prefix_repeat.carbon b/toolchain/parser/testdata/operators/prefix_repeat.carbon index bd17ff4487957..b9423409bc989 100644 --- a/toolchain/parser/testdata/operators/prefix_repeat.carbon +++ b/toolchain/parser/testdata/operators/prefix_repeat.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/operators/recover_infix_uneven_space_before.carbon b/toolchain/parser/testdata/operators/recover_infix_uneven_space_before.carbon index f722eac570047..32847992b3e4f 100644 --- a/toolchain/parser/testdata/operators/recover_infix_uneven_space_before.carbon +++ b/toolchain/parser/testdata/operators/recover_infix_uneven_space_before.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -17,5 +16,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_infix_uneven_space_before.carbon:[[@LINE+1]]:15: Whitespace missing after binary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_infix_uneven_space_before.carbon:[[@LINE+1]]:15: Whitespace missing after binary operator. var n: i8 = n *n; diff --git a/toolchain/parser/testdata/operators/recover_postfix_space.carbon b/toolchain/parser/testdata/operators/recover_postfix_space.carbon index 93accd196347f..9128479798076 100644 --- a/toolchain/parser/testdata/operators/recover_postfix_space.carbon +++ b/toolchain/parser/testdata/operators/recover_postfix_space.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'v'}, @@ -16,5 +15,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_postfix_space.carbon:[[@LINE+1]]:18: Whitespace is not allowed before this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_postfix_space.carbon:[[@LINE+1]]:18: Whitespace is not allowed before this unary operator. var v: type = i8 *; diff --git a/toolchain/parser/testdata/operators/recover_postfix_space_before_comma.carbon b/toolchain/parser/testdata/operators/recover_postfix_space_before_comma.carbon index 33b0c175beda0..05c38942875d7 100644 --- a/toolchain/parser/testdata/operators/recover_postfix_space_before_comma.carbon +++ b/toolchain/parser/testdata/operators/recover_postfix_space_before_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -21,5 +20,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_postfix_space_before_comma.carbon:[[@LINE+1]]:18: Whitespace is not allowed before this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_postfix_space_before_comma.carbon:[[@LINE+1]]:18: Whitespace is not allowed before this unary operator. var n: i8 = F(i8 *, 0); diff --git a/toolchain/parser/testdata/operators/recover_postfix_space_in_call.carbon b/toolchain/parser/testdata/operators/recover_postfix_space_in_call.carbon index f4fae68553cd7..1f32efe325011 100644 --- a/toolchain/parser/testdata/operators/recover_postfix_space_in_call.carbon +++ b/toolchain/parser/testdata/operators/recover_postfix_space_in_call.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -19,5 +18,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_postfix_space_in_call.carbon:[[@LINE+1]]:18: Whitespace is not allowed before this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_postfix_space_in_call.carbon:[[@LINE+1]]:18: Whitespace is not allowed before this unary operator. var n: i8 = F(i8 *); diff --git a/toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon b/toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon index a3b535fdd9afd..76edbb6ef484c 100644 --- a/toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon +++ b/toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'v'}, @@ -16,6 +15,6 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon:[[@LINE+2]]:18: Whitespace is not allowed before this unary operator. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon:[[@LINE+1]]:18: Whitespace is required after this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon:[[@LINE+2]]:18: Whitespace is not allowed before this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_postfix_space_surrounding.carbon:[[@LINE+1]]:18: Whitespace is required after this unary operator. var v: type = i8 * ; diff --git a/toolchain/parser/testdata/operators/recover_prefix_space.carbon b/toolchain/parser/testdata/operators/recover_prefix_space.carbon index 68748c1a712ae..fa5aac534fae3 100644 --- a/toolchain/parser/testdata/operators/recover_prefix_space.carbon +++ b/toolchain/parser/testdata/operators/recover_prefix_space.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -16,6 +15,6 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_prefix_space.carbon:[[@LINE+2]]:13: Whitespace is not allowed after this unary operator. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_prefix_space.carbon:[[@LINE+1]]:13: Whitespace is required before this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_prefix_space.carbon:[[@LINE+2]]:13: Whitespace is not allowed after this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_prefix_space.carbon:[[@LINE+1]]:13: Whitespace is required before this unary operator. var n: i8 = - n; diff --git a/toolchain/parser/testdata/operators/recover_prefix_uneven_space_with_assign.carbon b/toolchain/parser/testdata/operators/recover_prefix_uneven_space_with_assign.carbon index 11707abd72a48..6aa2d8a850cc6 100644 --- a/toolchain/parser/testdata/operators/recover_prefix_uneven_space_with_assign.carbon +++ b/toolchain/parser/testdata/operators/recover_prefix_uneven_space_with_assign.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'n'}, @@ -16,5 +15,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/recover_prefix_uneven_space_with_assign.carbon:[[@LINE+1]]:12: Whitespace is not allowed after this unary operator. +// CHECK:STDERR: toolchain/parser/testdata/operators/recover_prefix_uneven_space_with_assign.carbon:[[@LINE+1]]:12: Whitespace is not allowed after this unary operator. var n: i8 =- n; diff --git a/toolchain/parser/testdata/package/api.carbon b/toolchain/parser/testdata/package/api.carbon index 8869573a912a7..878a9da91a157 100644 --- a/toolchain/parser/testdata/package/api.carbon +++ b/toolchain/parser/testdata/package/api.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, diff --git a/toolchain/parser/testdata/package/api_library.carbon b/toolchain/parser/testdata/package/api_library.carbon index 12e10caf4e815..effb97a106184 100644 --- a/toolchain/parser/testdata/package/api_library.carbon +++ b/toolchain/parser/testdata/package/api_library.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, diff --git a/toolchain/parser/testdata/package/fail_extra_string.carbon b/toolchain/parser/testdata/package/fail_extra_string.carbon index 604aabd518a14..113851d12dc85 100644 --- a/toolchain/parser/testdata/package/fail_extra_string.carbon +++ b/toolchain/parser/testdata/package/fail_extra_string.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Foo'}, @@ -13,5 +12,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_extra_string.carbon:[[@LINE+1]]:27: Expected a `api` or `impl`. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_extra_string.carbon:[[@LINE+1]]:27: Expected a `api` or `impl`. package Foo library "bar" "baz"; diff --git a/toolchain/parser/testdata/package/fail_library_is_identifier.carbon b/toolchain/parser/testdata/package/fail_library_is_identifier.carbon index b6f7ec4a683d6..3b2bbd59043bf 100644 --- a/toolchain/parser/testdata/package/fail_library_is_identifier.carbon +++ b/toolchain/parser/testdata/package/fail_library_is_identifier.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, @@ -11,5 +10,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_library_is_identifier.carbon:[[@LINE+1]]:26: Expected a string literal to specify the library name. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_library_is_identifier.carbon:[[@LINE+1]]:26: Expected a string literal to specify the library name. package Geometry library Shapes api; diff --git a/toolchain/parser/testdata/package/fail_library_skips_name.carbon b/toolchain/parser/testdata/package/fail_library_skips_name.carbon index e2d78291d914d..e1febd2167e34 100644 --- a/toolchain/parser/testdata/package/fail_library_skips_name.carbon +++ b/toolchain/parser/testdata/package/fail_library_skips_name.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_library_skips_name.carbon:[[@LINE+1]]:9: Expected identifier after `package`. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_library_skips_name.carbon:[[@LINE+1]]:9: Expected identifier after `package`. package library "Shapes" api; diff --git a/toolchain/parser/testdata/package/fail_name_is_keyword.carbon b/toolchain/parser/testdata/package/fail_name_is_keyword.carbon index 39a678e2ccb7b..459a58b889527 100644 --- a/toolchain/parser/testdata/package/fail_name_is_keyword.carbon +++ b/toolchain/parser/testdata/package/fail_name_is_keyword.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_name_is_keyword.carbon:[[@LINE+1]]:9: Expected identifier after `package`. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_name_is_keyword.carbon:[[@LINE+1]]:9: Expected identifier after `package`. package fn; diff --git a/toolchain/parser/testdata/package/fail_no_name.carbon b/toolchain/parser/testdata/package/fail_no_name.carbon index 8a54c4f293b06..5125aeb8abe9b 100644 --- a/toolchain/parser/testdata/package/fail_no_name.carbon +++ b/toolchain/parser/testdata/package/fail_no_name.carbon @@ -3,12 +3,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 2}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_no_name.carbon:[[@LINE+1]]:8: Expected identifier after `package`. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_no_name.carbon:[[@LINE+1]]:8: Expected identifier after `package`. package; diff --git a/toolchain/parser/testdata/package/fail_no_semi.carbon b/toolchain/parser/testdata/package/fail_no_semi.carbon index ceaa48908297c..d85b4313cff6a 100644 --- a/toolchain/parser/testdata/package/fail_no_semi.carbon +++ b/toolchain/parser/testdata/package/fail_no_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, @@ -12,5 +11,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_no_semi.carbon:[[@LINE+1]]:21: Expected `;` to end package directive. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_no_semi.carbon:[[@LINE+1]]:21: Expected `;` to end package directive. package Geometry api diff --git a/toolchain/parser/testdata/package/fail_no_type.carbon b/toolchain/parser/testdata/package/fail_no_type.carbon index 42c89f1c8c275..2f16954118f70 100644 --- a/toolchain/parser/testdata/package/fail_no_type.carbon +++ b/toolchain/parser/testdata/package/fail_no_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, @@ -11,5 +10,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_no_type.carbon:[[@LINE+1]]:17: Expected a `api` or `impl`. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_no_type.carbon:[[@LINE+1]]:17: Expected a `api` or `impl`. package Geometry; diff --git a/toolchain/parser/testdata/package/fail_omit_library_keyword.carbon b/toolchain/parser/testdata/package/fail_omit_library_keyword.carbon index 760d1b9087062..cd8d94b992e47 100644 --- a/toolchain/parser/testdata/package/fail_omit_library_keyword.carbon +++ b/toolchain/parser/testdata/package/fail_omit_library_keyword.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, @@ -11,5 +10,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/package/fail_omit_library_keyword.carbon:[[@LINE+1]]:18: Missing `library` keyword. +// CHECK:STDERR: toolchain/parser/testdata/package/fail_omit_library_keyword.carbon:[[@LINE+1]]:18: Missing `library` keyword. package Geometry "Shapes" api; diff --git a/toolchain/parser/testdata/package/impl.carbon b/toolchain/parser/testdata/package/impl.carbon index 6786ec31a737e..6cefd7bd4a3ba 100644 --- a/toolchain/parser/testdata/package/impl.carbon +++ b/toolchain/parser/testdata/package/impl.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, diff --git a/toolchain/parser/testdata/package/impl_library.carbon b/toolchain/parser/testdata/package/impl_library.carbon index 5efaf45bed27e..f4fa3f4e9acaf 100644 --- a/toolchain/parser/testdata/package/impl_library.carbon +++ b/toolchain/parser/testdata/package/impl_library.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'Geometry'}, diff --git a/toolchain/parser/testdata/return/basic.carbon b/toolchain/parser/testdata/return/basic.carbon index 9ae5f87adbfc3..6b51d3d2c912a 100644 --- a/toolchain/parser/testdata/return/basic.carbon +++ b/toolchain/parser/testdata/return/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/return/expr.carbon b/toolchain/parser/testdata/return/expr.carbon index 86abb96784338..ccbd2bff741a8 100644 --- a/toolchain/parser/testdata/return/expr.carbon +++ b/toolchain/parser/testdata/return/expr.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/return/fail_expr_no_semi.carbon b/toolchain/parser/testdata/return/fail_expr_no_semi.carbon index 3d303f246b317..3d42eeed71f48 100644 --- a/toolchain/parser/testdata/return/fail_expr_no_semi.carbon +++ b/toolchain/parser/testdata/return/fail_expr_no_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -19,5 +18,5 @@ fn F() { return x -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/return/fail_expr_no_semi.carbon:[[@LINE+1]]:1: Expected `;` after `return`. +// CHECK:STDERR: toolchain/parser/testdata/return/fail_expr_no_semi.carbon:[[@LINE+1]]:1: Expected `;` after `return`. } diff --git a/toolchain/parser/testdata/return/fail_no_semi.carbon b/toolchain/parser/testdata/return/fail_no_semi.carbon index e79b6b56b51ff..54457d0e7e3de 100644 --- a/toolchain/parser/testdata/return/fail_no_semi.carbon +++ b/toolchain/parser/testdata/return/fail_no_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -19,6 +18,6 @@ fn F() { return -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/return/fail_no_semi.carbon:[[@LINE+2]]:1: Expected expression. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/return/fail_no_semi.carbon:[[@LINE+1]]:1: Expected `;` after `return`. +// CHECK:STDERR: toolchain/parser/testdata/return/fail_no_semi.carbon:[[@LINE+2]]:1: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/return/fail_no_semi.carbon:[[@LINE+1]]:1: Expected `;` after `return`. } diff --git a/toolchain/parser/testdata/struct/fail_comma_only.carbon b/toolchain/parser/testdata/struct/fail_comma_only.carbon index bfbb0115def59..006e12e9f242c 100644 --- a/toolchain/parser/testdata/struct/fail_comma_only.carbon +++ b/toolchain/parser/testdata/struct/fail_comma_only.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -19,5 +18,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_comma_only.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_comma_only.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. var x: {,} = {}; diff --git a/toolchain/parser/testdata/struct/fail_comma_repeat_in_type.carbon b/toolchain/parser/testdata/struct/fail_comma_repeat_in_type.carbon index 213bd95b4c1ce..d8f1dd70f97be 100644 --- a/toolchain/parser/testdata/struct/fail_comma_repeat_in_type.carbon +++ b/toolchain/parser/testdata/struct/fail_comma_repeat_in_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -24,5 +23,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_comma_repeat_in_type.carbon:[[@LINE+1]]:17: Expected `.field: field_type`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_comma_repeat_in_type.carbon:[[@LINE+1]]:17: Expected `.field: field_type`. var x: {.a: i32,,} = {}; diff --git a/toolchain/parser/testdata/struct/fail_comma_repeat_in_value.carbon b/toolchain/parser/testdata/struct/fail_comma_repeat_in_value.carbon index 4de5fc08239d7..cbce89274aad9 100644 --- a/toolchain/parser/testdata/struct/fail_comma_repeat_in_value.carbon +++ b/toolchain/parser/testdata/struct/fail_comma_repeat_in_value.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -24,5 +23,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_comma_repeat_in_value.carbon:[[@LINE+1]]:16: Expected `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_comma_repeat_in_value.carbon:[[@LINE+1]]:16: Expected `.field = value`. var x: {.a = 0,,} = {}; diff --git a/toolchain/parser/testdata/struct/fail_dot_only.carbon b/toolchain/parser/testdata/struct/fail_dot_only.carbon index 2a1300b7d4028..97cef75d67771 100644 --- a/toolchain/parser/testdata/struct/fail_dot_only.carbon +++ b/toolchain/parser/testdata/struct/fail_dot_only.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -20,5 +19,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_dot_only.carbon:[[@LINE+1]]:10: Expected identifier after `.`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_dot_only.carbon:[[@LINE+1]]:10: Expected identifier after `.`. var x: {.} = {}; diff --git a/toolchain/parser/testdata/struct/fail_dot_string_colon.carbon b/toolchain/parser/testdata/struct/fail_dot_string_colon.carbon index cd3a7e7d890d1..092b27d461dfa 100644 --- a/toolchain/parser/testdata/struct/fail_dot_string_colon.carbon +++ b/toolchain/parser/testdata/struct/fail_dot_string_colon.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -26,5 +25,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_dot_string_colon.carbon:[[@LINE+1]]:10: Expected identifier after `.`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_dot_string_colon.carbon:[[@LINE+1]]:10: Expected identifier after `.`. var x: {."hello": i32, .y: i32} = {}; diff --git a/toolchain/parser/testdata/struct/fail_dot_string_equals.carbon b/toolchain/parser/testdata/struct/fail_dot_string_equals.carbon index e511116b9ea52..3bd4e84b11cb3 100644 --- a/toolchain/parser/testdata/struct/fail_dot_string_equals.carbon +++ b/toolchain/parser/testdata/struct/fail_dot_string_equals.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -26,5 +25,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_dot_string_equals.carbon:[[@LINE+1]]:10: Expected identifier after `.`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_dot_string_equals.carbon:[[@LINE+1]]:10: Expected identifier after `.`. var x: {."hello" = 0, .y = 4} = {}; diff --git a/toolchain/parser/testdata/struct/fail_extra_token_in_type.carbon b/toolchain/parser/testdata/struct/fail_extra_token_in_type.carbon index 6e79f65d6cc63..8ff218db9827d 100644 --- a/toolchain/parser/testdata/struct/fail_extra_token_in_type.carbon +++ b/toolchain/parser/testdata/struct/fail_extra_token_in_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -25,5 +24,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_extra_token_in_type.carbon:[[@LINE+1]]:17: Expected `,` or `}`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_extra_token_in_type.carbon:[[@LINE+1]]:17: Expected `,` or `}`. var x: {.a: i32 banana} = {.a = 0}; diff --git a/toolchain/parser/testdata/struct/fail_extra_token_in_value.carbon b/toolchain/parser/testdata/struct/fail_extra_token_in_value.carbon index 901f0f1cf6122..a450d48309e22 100644 --- a/toolchain/parser/testdata/struct/fail_extra_token_in_value.carbon +++ b/toolchain/parser/testdata/struct/fail_extra_token_in_value.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -25,5 +24,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_extra_token_in_value.carbon:[[@LINE+1]]:28: Expected `,` or `}`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_extra_token_in_value.carbon:[[@LINE+1]]:28: Expected `,` or `}`. var x: {.a: i32} = {.a = 0 banana}; diff --git a/toolchain/parser/testdata/struct/fail_identifier_colon.carbon b/toolchain/parser/testdata/struct/fail_identifier_colon.carbon index 3bf338b9b8f88..ba9ae32b292a2 100644 --- a/toolchain/parser/testdata/struct/fail_identifier_colon.carbon +++ b/toolchain/parser/testdata/struct/fail_identifier_colon.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -18,5 +17,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_identifier_colon.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_identifier_colon.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. var x: {a:} = {}; diff --git a/toolchain/parser/testdata/struct/fail_identifier_equals.carbon b/toolchain/parser/testdata/struct/fail_identifier_equals.carbon index 0a593a89e7a66..aa7aa30b1ca7d 100644 --- a/toolchain/parser/testdata/struct/fail_identifier_equals.carbon +++ b/toolchain/parser/testdata/struct/fail_identifier_equals.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -18,5 +17,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_identifier_equals.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_identifier_equals.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. var x: {a=} = {}; diff --git a/toolchain/parser/testdata/struct/fail_identifier_only.carbon b/toolchain/parser/testdata/struct/fail_identifier_only.carbon index 12275ff05590d..4e08bc83d8ff2 100644 --- a/toolchain/parser/testdata/struct/fail_identifier_only.carbon +++ b/toolchain/parser/testdata/struct/fail_identifier_only.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -18,5 +17,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_identifier_only.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_identifier_only.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. var x: {a} = {}; diff --git a/toolchain/parser/testdata/struct/fail_missing_type.carbon b/toolchain/parser/testdata/struct/fail_missing_type.carbon index f13c22fc0bc3a..8273e09345533 100644 --- a/toolchain/parser/testdata/struct/fail_missing_type.carbon +++ b/toolchain/parser/testdata/struct/fail_missing_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -21,5 +20,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_missing_type.carbon:[[@LINE+1]]:12: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_missing_type.carbon:[[@LINE+1]]:12: Expected expression. var x: {.a:} = {}; diff --git a/toolchain/parser/testdata/struct/fail_missing_value.carbon b/toolchain/parser/testdata/struct/fail_missing_value.carbon index e7874cb78f1b1..f2856bf7f90b0 100644 --- a/toolchain/parser/testdata/struct/fail_missing_value.carbon +++ b/toolchain/parser/testdata/struct/fail_missing_value.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -21,5 +20,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_missing_value.carbon:[[@LINE+1]]:12: Expected expression. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_missing_value.carbon:[[@LINE+1]]:12: Expected expression. var x: {.a=} = {}; diff --git a/toolchain/parser/testdata/struct/fail_mix_type_and_value.carbon b/toolchain/parser/testdata/struct/fail_mix_type_and_value.carbon index 9efa1497b80f1..d67915f417cb0 100644 --- a/toolchain/parser/testdata/struct/fail_mix_type_and_value.carbon +++ b/toolchain/parser/testdata/struct/fail_mix_type_and_value.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -25,5 +24,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_mix_type_and_value.carbon:[[@LINE+1]]:21: Expected `.field: field_type`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_mix_type_and_value.carbon:[[@LINE+1]]:21: Expected `.field: field_type`. var x: {.a: i32, .b = 0} = {}; diff --git a/toolchain/parser/testdata/struct/fail_mix_value_and_type.carbon b/toolchain/parser/testdata/struct/fail_mix_value_and_type.carbon index 3e7ada9d4a8a0..8ba22a09bd769 100644 --- a/toolchain/parser/testdata/struct/fail_mix_value_and_type.carbon +++ b/toolchain/parser/testdata/struct/fail_mix_value_and_type.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -23,5 +22,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_mix_value_and_type.carbon:[[@LINE+1]]:17: Expected `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_mix_value_and_type.carbon:[[@LINE+1]]:17: Expected `.field = value`. var x: {.a = 0, b: i32} = {}; diff --git a/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon b/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon index 125d664f87a53..2383e20759439 100644 --- a/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon +++ b/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -48,10 +47,10 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+2]]:25: Expected `.field = value`. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+1]]:29: Expected `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+2]]:25: Expected `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+1]]:29: Expected `.field = value`. var x: i32 = {.a = 1, .b, .c: i32}; -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+2]]:26: Expected `.field: field_type`. -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+1]]:31: Expected `.field: field_type`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+2]]:26: Expected `.field: field_type`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_mix_with_unknown.carbon:[[@LINE+1]]:31: Expected `.field: field_type`. var x: i32 = {.a: i32, .b, .c = 1}; diff --git a/toolchain/parser/testdata/struct/fail_no_colon_or_equals.carbon b/toolchain/parser/testdata/struct/fail_no_colon_or_equals.carbon index 070a7fb5aefc5..8935dba730678 100644 --- a/toolchain/parser/testdata/struct/fail_no_colon_or_equals.carbon +++ b/toolchain/parser/testdata/struct/fail_no_colon_or_equals.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -20,5 +19,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_no_colon_or_equals.carbon:[[@LINE+1]]:11: Expected `.field: field_type` or `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_no_colon_or_equals.carbon:[[@LINE+1]]:11: Expected `.field: field_type` or `.field = value`. var x: {.a} = {}; diff --git a/toolchain/parser/testdata/struct/fail_type_no_designator.carbon b/toolchain/parser/testdata/struct/fail_type_no_designator.carbon index d1085fa888f04..ce95a10fea131 100644 --- a/toolchain/parser/testdata/struct/fail_type_no_designator.carbon +++ b/toolchain/parser/testdata/struct/fail_type_no_designator.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, @@ -18,5 +17,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/struct/fail_type_no_designator.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. +// CHECK:STDERR: toolchain/parser/testdata/struct/fail_type_no_designator.carbon:[[@LINE+1]]:9: Expected `.field: field_type` or `.field = value`. var x: {i32} = {}; diff --git a/toolchain/parser/testdata/struct/no_entries.carbon b/toolchain/parser/testdata/struct/no_entries.carbon index c95dd1cae5358..5847e456a7b56 100644 --- a/toolchain/parser/testdata/struct/no_entries.carbon +++ b/toolchain/parser/testdata/struct/no_entries.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'y'}, diff --git a/toolchain/parser/testdata/struct/one_entry_no_comma.carbon b/toolchain/parser/testdata/struct/one_entry_no_comma.carbon index 6afd717fdb2d1..02a73f6e15774 100644 --- a/toolchain/parser/testdata/struct/one_entry_no_comma.carbon +++ b/toolchain/parser/testdata/struct/one_entry_no_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'z'}, diff --git a/toolchain/parser/testdata/struct/one_entry_with_comma.carbon b/toolchain/parser/testdata/struct/one_entry_with_comma.carbon index d42b207180319..d59a5880296fc 100644 --- a/toolchain/parser/testdata/struct/one_entry_with_comma.carbon +++ b/toolchain/parser/testdata/struct/one_entry_with_comma.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'z'}, diff --git a/toolchain/parser/testdata/struct/two_entries.carbon b/toolchain/parser/testdata/struct/two_entries.carbon index 02867b71172e0..64dcf863fdf36 100644 --- a/toolchain/parser/testdata/struct/two_entries.carbon +++ b/toolchain/parser/testdata/struct/two_entries.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, diff --git a/toolchain/parser/testdata/tuple/nested.carbon b/toolchain/parser/testdata/tuple/nested.carbon index 5f55602164d59..15fdbd4e4376e 100644 --- a/toolchain/parser/testdata/tuple/nested.carbon +++ b/toolchain/parser/testdata/tuple/nested.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'y'}, diff --git a/toolchain/parser/testdata/tuple/two_entries.carbon b/toolchain/parser/testdata/tuple/two_entries.carbon index 7c3fdbd77973f..aef4367b7e3fe 100644 --- a/toolchain/parser/testdata/tuple/two_entries.carbon +++ b/toolchain/parser/testdata/tuple/two_entries.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'x'}, diff --git a/toolchain/parser/testdata/var/fail_bad_name.carbon b/toolchain/parser/testdata/var/fail_bad_name.carbon index f1b59db3f57e1..b19112dbc9f41 100644 --- a/toolchain/parser/testdata/var/fail_bad_name.carbon +++ b/toolchain/parser/testdata/var/fail_bad_name.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: '*', has_error: yes}, @@ -13,5 +12,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/var/fail_bad_name.carbon:[[@LINE+1]]:5: Expected pattern in `var` declaration. +// CHECK:STDERR: toolchain/parser/testdata/var/fail_bad_name.carbon:[[@LINE+1]]:5: Expected pattern in `var` declaration. var *; diff --git a/toolchain/parser/testdata/var/fail_empty.carbon b/toolchain/parser/testdata/var/fail_empty.carbon index 6183c4407d8a9..b33018175cbad 100644 --- a/toolchain/parser/testdata/var/fail_empty.carbon +++ b/toolchain/parser/testdata/var/fail_empty.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: ';', has_error: yes}, @@ -13,5 +12,5 @@ // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] -// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/var/fail_empty.carbon:[[@LINE+1]]:4: Expected pattern in `var` declaration. +// CHECK:STDERR: toolchain/parser/testdata/var/fail_empty.carbon:[[@LINE+1]]:4: Expected pattern in `var` declaration. var; diff --git a/toolchain/parser/testdata/var/var.carbon b/toolchain/parser/testdata/var/var.carbon index 0460570cd10bf..a2624811ef52f 100644 --- a/toolchain/parser/testdata/var/var.carbon +++ b/toolchain/parser/testdata/var/var.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'v'}, diff --git a/toolchain/parser/testdata/while/basic.carbon b/toolchain/parser/testdata/while/basic.carbon index bb0fa469106f9..9466e569aa311 100644 --- a/toolchain/parser/testdata/while/basic.carbon +++ b/toolchain/parser/testdata/while/basic.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, diff --git a/toolchain/parser/testdata/while/fail_no_semi.carbon b/toolchain/parser/testdata/while/fail_no_semi.carbon index ea3fae0eaed5b..db9c4c4f9f245 100644 --- a/toolchain/parser/testdata/while/fail_no_semi.carbon +++ b/toolchain/parser/testdata/while/fail_no_semi.carbon @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -40,11 +39,11 @@ fn F() { while (a) { if (b) { break - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/while/fail_no_semi.carbon:[[@LINE+1]]:5: Expected `;` after `break`. + // CHECK:STDERR: toolchain/parser/testdata/while/fail_no_semi.carbon:[[@LINE+1]]:5: Expected `;` after `break`. } if (c) { continue - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/while/fail_no_semi.carbon:[[@LINE+1]]:5: Expected `;` after `continue`. + // CHECK:STDERR: toolchain/parser/testdata/while/fail_no_semi.carbon:[[@LINE+1]]:5: Expected `;` after `continue`. } } } diff --git a/toolchain/parser/testdata/while/fail_unbraced.carbon b/toolchain/parser/testdata/while/fail_unbraced.carbon index 14f88f1f007e5..3bf0461172123 100644 --- a/toolchain/parser/testdata/while/fail_unbraced.carbon +++ b/toolchain/parser/testdata/while/fail_unbraced.carbon @@ -4,7 +4,6 @@ // // TODO: This should have an error. // AUTOUPDATE -// RUN: %{not} %{carbon-run-parser} // CHECK:STDOUT: [ // CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, // CHECK:STDOUT: {kind: 'DeclaredName', text: 'F'}, @@ -25,6 +24,6 @@ fn F() { while (a) - // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/while/fail_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + // CHECK:STDERR: toolchain/parser/testdata/while/fail_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. break; } diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index eea142aa392f3..34be5123f6371 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -2,8 +2,8 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -load("//testing/file_test:rules.bzl", "file_test") load("//bazel/sh_run:rules.bzl", "glob_sh_run") +load("//testing/file_test:rules.bzl", "file_test") package(default_visibility = ["//visibility:public"]) @@ -114,9 +114,8 @@ file_test( srcs = ["semantics_file_test.cpp"], tests = glob(["testdata/**/*.carbon"]), deps = [ - ":semantics_ir", "//testing/file_test:file_test_base", - "//toolchain/diagnostics:diagnostic_emitter", + "//toolchain/driver", "@com_google_googletest//:gtest", "@llvm-project//llvm:Support", ], diff --git a/toolchain/semantics/semantics_file_test.cpp b/toolchain/semantics/semantics_file_test.cpp index 6d1ff1799a521..30d6fd9c54d13 100644 --- a/toolchain/semantics/semantics_file_test.cpp +++ b/toolchain/semantics/semantics_file_test.cpp @@ -10,8 +10,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" #include "testing/file_test/file_test_base.h" -#include "toolchain/diagnostics/diagnostic_emitter.h" -#include "toolchain/semantics/semantics_ir.h" +#include "toolchain/driver/driver.h" namespace Carbon::Testing { namespace { @@ -22,15 +21,8 @@ class SemanticsFileTest : public FileTestBase { void RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) override { - StreamDiagnosticConsumer consumer(stderr); - llvm::Expected source = SourceBuffer::CreateFromFile(path()); - TokenizedBuffer tokens = TokenizedBuffer::Lex(*source, consumer); - ParseTree parse_tree = - ParseTree::Parse(tokens, consumer, /*vlog_stream=*/nullptr); - SemanticsIR builtin_ir = SemanticsIR::MakeBuiltinIR(); - SemanticsIR semantics_ir = SemanticsIR::MakeFromParseTree( - builtin_ir, tokens, parse_tree, consumer, /*vlog_stream=*/nullptr); - semantics_ir.Print(stdout); + Driver driver(stdout, stderr); + driver.RunFullCommand({"dump", "semantics-ir", path()}); } }; diff --git a/toolchain/semantics/testdata/lit.cfg.py b/toolchain/semantics/testdata/lit.cfg.py deleted file mode 120000 index c323f8a5e8da2..0000000000000 --- a/toolchain/semantics/testdata/lit.cfg.py +++ /dev/null @@ -1 +0,0 @@ -../../../bazel/testing/lit.cfg.py \ No newline at end of file From c41e6bb46b07fdd333f410cc66255f8da50a22fc Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 22:32:10 +0000 Subject: [PATCH 16/29] fail_example --- testing/file_test/fail_example.carbon | 5 +++++ testing/file_test/file_test_base.cpp | 7 +++++- testing/file_test/file_test_base.h | 5 +++-- testing/file_test/file_test_base_test.cpp | 27 ++++++++++++++--------- 4 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 testing/file_test/fail_example.carbon diff --git a/testing/file_test/fail_example.carbon b/testing/file_test/fail_example.carbon new file mode 100644 index 0000000000000..2516b5d814cff --- /dev/null +++ b/testing/file_test/fail_example.carbon @@ -0,0 +1,5 @@ +// 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 + +// CHECK:STDERR: Oops diff --git a/testing/file_test/file_test_base.cpp b/testing/file_test/file_test_base.cpp index 951cada90eaff..30782707ba3db 100644 --- a/testing/file_test/file_test_base.cpp +++ b/testing/file_test/file_test_base.cpp @@ -14,6 +14,8 @@ static std::string* subset_target = nullptr; namespace Carbon::Testing { +using ::testing::Eq; + void FileTestBase::RegisterTests( const char* fixture_label, const std::vector& paths, std::function factory) { @@ -78,10 +80,13 @@ auto FileTestBase::TestBody() -> void { std::string stderr; llvm::raw_string_ostream stdout_ostream(stdout); llvm::raw_string_ostream stderr_ostream(stderr); - RunOverFile(stdout_ostream, stderr_ostream); + bool run_succeeded = RunOverFile(stdout_ostream, stderr_ostream); if (HasFailure()) { return; } + EXPECT_THAT(!filename().starts_with("fail_"), Eq(run_succeeded)) + << "Tests should be prefixed with `fail_` if and only if running them " + "is expected to fail."; // Check results. EXPECT_THAT(SplitOutput(stdout), ElementsAreArray(expected_stdout)); diff --git a/testing/file_test/file_test_base.h b/testing/file_test/file_test_base.h index da3e79bba571b..7177504c76810 100644 --- a/testing/file_test/file_test_base.h +++ b/testing/file_test/file_test_base.h @@ -40,9 +40,10 @@ class FileTestBase : public testing::Test { std::function factory); // Implemented by children to run the test. Called by the TestBody - // implementation, which will validate stdout and stderr. + // implementation, which will validate stdout and stderr. The return value + // should be false when "fail_" is in the filename. virtual auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) - -> void = 0; + -> bool = 0; // Runs a test and compares output. This keeps output split by line so that // issues are a little easier to identify by the different line. diff --git a/testing/file_test/file_test_base_test.cpp b/testing/file_test/file_test_base_test.cpp index 437f7793e5260..c8124d5c2554e 100644 --- a/testing/file_test/file_test_base_test.cpp +++ b/testing/file_test/file_test_base_test.cpp @@ -19,16 +19,23 @@ class FileTestBaseTest : public FileTestBase { public: explicit FileTestBaseTest(llvm::StringRef path) : FileTestBase(path) {} - void RunOverFile(llvm::raw_ostream& stdout_stream, - llvm::raw_ostream& /*stderr*/) override { - ASSERT_THAT(filename(), testing::StrEq("example.carbon")); - - stdout_stream << "something\n" - "\n" - "8: Line delta\n" - "7: Negative line delta\n" - "+*[]{}\n" - "Foo baz\n"; + auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) + -> bool override { + if (filename() == "example.carbon") { + stdout << "something\n" + "\n" + "8: Line delta\n" + "7: Negative line delta\n" + "+*[]{}\n" + "Foo baz\n"; + return true; + } else if (filename() == "fail_example.carbon") { + stderr << "Oops\n"; + return false; + } else { + ADD_FAILURE() << "Unexpected file: " << path().str(); + return false; + } } }; From fd82ddecc7969c19f472e3158237f2702b2feca3 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 23:21:28 +0000 Subject: [PATCH 17/29] x --- toolchain/lexer/lexer_file_test.cpp | 6 +++--- toolchain/lowering/lowering_file_test.cpp | 6 +++--- toolchain/parser/parse_tree_file_test.cpp | 6 +++--- toolchain/semantics/semantics_file_test.cpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/toolchain/lexer/lexer_file_test.cpp b/toolchain/lexer/lexer_file_test.cpp index a57e4e92bee9e..a9c0222c83d08 100644 --- a/toolchain/lexer/lexer_file_test.cpp +++ b/toolchain/lexer/lexer_file_test.cpp @@ -19,10 +19,10 @@ class LexerFileTest : public FileTestBase { public: explicit LexerFileTest(llvm::StringRef path) : FileTestBase(path) {} - void RunOverFile(llvm::raw_ostream& stdout, - llvm::raw_ostream& stderr) override { + auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) + -> bool override { Driver driver(stdout, stderr); - driver.RunFullCommand({"dump", "tokens", path()}); + return driver.RunFullCommand({"dump", "tokens", path()}); } }; diff --git a/toolchain/lowering/lowering_file_test.cpp b/toolchain/lowering/lowering_file_test.cpp index f23ad5b5b93ac..6114cfd545adb 100644 --- a/toolchain/lowering/lowering_file_test.cpp +++ b/toolchain/lowering/lowering_file_test.cpp @@ -19,10 +19,10 @@ class LoweringFileTest : public FileTestBase { public: explicit LoweringFileTest(llvm::StringRef path) : FileTestBase(path) {} - void RunOverFile(llvm::raw_ostream& stdout, - llvm::raw_ostream& stderr) override { + auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) + -> bool override { Driver driver(stdout, stderr); - driver.RunFullCommand({"dump", "llvm-ir", path()}); + return driver.RunFullCommand({"dump", "llvm-ir", path()}); } }; diff --git a/toolchain/parser/parse_tree_file_test.cpp b/toolchain/parser/parse_tree_file_test.cpp index e754299553e4f..6a7b5bead424f 100644 --- a/toolchain/parser/parse_tree_file_test.cpp +++ b/toolchain/parser/parse_tree_file_test.cpp @@ -19,10 +19,10 @@ class ParserFileTest : public FileTestBase { public: explicit ParserFileTest(llvm::StringRef path) : FileTestBase(path) {} - void RunOverFile(llvm::raw_ostream& stdout, - llvm::raw_ostream& stderr) override { + auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) + -> bool override { Driver driver(stdout, stderr); - driver.RunFullCommand({"dump", "parse-tree", path()}); + return driver.RunFullCommand({"dump", "parse-tree", path()}); } }; diff --git a/toolchain/semantics/semantics_file_test.cpp b/toolchain/semantics/semantics_file_test.cpp index 30d6fd9c54d13..fc8ba251ae6ee 100644 --- a/toolchain/semantics/semantics_file_test.cpp +++ b/toolchain/semantics/semantics_file_test.cpp @@ -19,10 +19,10 @@ class SemanticsFileTest : public FileTestBase { public: explicit SemanticsFileTest(llvm::StringRef path) : FileTestBase(path) {} - void RunOverFile(llvm::raw_ostream& stdout, - llvm::raw_ostream& stderr) override { + auto RunOverFile(llvm::raw_ostream& stdout, llvm::raw_ostream& stderr) + -> bool override { Driver driver(stdout, stderr); - driver.RunFullCommand({"dump", "semantics-ir", path()}); + return driver.RunFullCommand({"dump", "semantics-ir", path()}); } }; From 25c75c23fda7f2007069f527fe5a5ce59441f5b0 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 23:56:01 +0000 Subject: [PATCH 18/29] x --- bazel/testing/lit_autoupdate_base.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bazel/testing/lit_autoupdate_base.py b/bazel/testing/lit_autoupdate_base.py index 647b6266e73ba..b067c2916cb1d 100755 --- a/bazel/testing/lit_autoupdate_base.py +++ b/bazel/testing/lit_autoupdate_base.py @@ -316,13 +316,14 @@ def get_matchable_test_output( # Escape things that mirror FileCheck special characters. out = out.replace("{{", "{{[{][{]}}") out = out.replace("[[", "{{[[][[]}}") - # `lit` uses full paths to the test file, so use a regex to ignore paths - # when used. if for_lit: + # `lit` uses full paths to the test file, so use a regex to ignore paths + # when used. out = out.replace(test, f"{{{{.*}}}}/{test}") - # Replacing runfiles is a more complex replacement. - # We have some things show up under runfiles; this removes them. out = bazel_runfiles.sub("{{.*}}/", out) + else: + # When not using `lit`, the runfiles path is removed. + out = bazel_runfiles.sub("", out) out_lines = out.splitlines() for i, line in enumerate(out_lines): From f285b6bb2e59e64ecc96824e6efd1ea3f67c6b1f Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 9 May 2023 23:57:58 +0000 Subject: [PATCH 19/29] x --- testing/file_test/file_test_base_test.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/testing/file_test/file_test_base_test.cpp b/testing/file_test/file_test_base_test.cpp index c8124d5c2554e..51ff16a1b834b 100644 --- a/testing/file_test/file_test_base_test.cpp +++ b/testing/file_test/file_test_base_test.cpp @@ -42,10 +42,9 @@ class FileTestBaseTest : public FileTestBase { } // namespace auto RegisterFileTests(const std::vector& paths) -> void { - Carbon::Testing::FileTestBaseTest::RegisterTests( - "FileTestBaseTest", paths, [](llvm::StringRef path) { - return new Carbon::Testing::FileTestBaseTest(path); - }); + FileTestBaseTest::RegisterTests( + "FileTestBaseTest", paths, + [](llvm::StringRef path) { return new FileTestBaseTest(path); }); } } // namespace Carbon::Testing From 1fa126a3865cce6c2e2ff7d6ce1ef292f5d9b2b6 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Thu, 11 May 2023 21:09:38 +0000 Subject: [PATCH 20/29] x --- toolchain/lowering/lowering_context.cpp | 50 ++++++++++-- toolchain/lowering/lowering_context.h | 32 ++++++-- toolchain/lowering/lowering_handle.cpp | 80 +++++++++++++------ .../function/definition/params_one.carbon | 2 +- .../function/definition/params_two.carbon | 2 +- .../function/definition/params_zero.carbon | 2 +- .../lowering/testdata/return/no_value.carbon | 2 +- .../lowering/testdata/struct/empty.carbon | 21 +++++ .../testdata/struct/member_access.carbon | 30 +++++++ .../lowering/testdata/struct/one_entry.carbon | 27 +++++++ .../testdata/struct/two_entries.carbon | 27 +++++++ toolchain/lowering/testdata/var/local.carbon | 19 +++++ 12 files changed, 252 insertions(+), 42 deletions(-) create mode 100644 toolchain/lowering/testdata/struct/empty.carbon create mode 100644 toolchain/lowering/testdata/struct/member_access.carbon create mode 100644 toolchain/lowering/testdata/struct/one_entry.carbon create mode 100644 toolchain/lowering/testdata/struct/two_entries.carbon create mode 100644 toolchain/lowering/testdata/var/local.carbon diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp index 9cf3764225f39..08a0d7e3e4342 100644 --- a/toolchain/lowering/lowering_context.cpp +++ b/toolchain/lowering/lowering_context.cpp @@ -5,6 +5,7 @@ #include "toolchain/lowering/lowering_context.h" #include "toolchain/semantics/semantics_ir.h" +#include "toolchain/semantics/semantics_node_kind.h" namespace Carbon { @@ -47,19 +48,56 @@ auto LoweringContext::LowerBlock(SemanticsNodeBlockId block_id) -> void { } } -auto LoweringContext::LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type* { - CARBON_CHECK(node_id.is_valid()); +auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id) + -> llvm::Type* { switch (node_id.index) { + case SemanticsBuiltinKind::EmptyStructType.AsInt(): case SemanticsBuiltinKind::EmptyTuple.AsInt(): - // TODO: Should probably switch this to an actual empty tuple in the - // future, but it's implemented as void for now. - return builder_.getVoidTy(); + case SemanticsBuiltinKind::EmptyTupleType.AsInt(): + // Represent empty data as 0-length arrays. + // TODO: Work to remove EmptyTuple here. + return llvm::ArrayType::get(builder_.getInt8Ty(), 0); + case SemanticsBuiltinKind::FloatingPointType.AsInt(): + // TODO: Handle different sizes. + return builder_.getDoubleTy(); case SemanticsBuiltinKind::IntegerType.AsInt(): // TODO: Handle different sizes. return builder_.getInt32Ty(); - default: + } + + auto node = semantics_ir_->GetNode(node_id); + switch (node.kind()) { + case SemanticsNodeKind::StructType: { + auto refs = semantics_ir_->GetNodeBlock(node.GetAsStructType().second); + llvm::SmallVector subtypes; + subtypes.reserve(refs.size()); + for (auto ref_id : refs) { + auto type_id = semantics_ir_->GetNode(ref_id).type_id(); + // TODO: Handle recursive types. The restriction for builtins prevents + // recursion while still letting them cache. + CARBON_CHECK(type_id.index < SemanticsBuiltinKind::ValidCount) + << type_id; + subtypes.push_back(GetLoweredNodeAsType(type_id)); + } + auto* type = llvm::StructType::create(*llvm_context_, subtypes); + lowered_nodes_[node_id.index] = type; + return type; + } + default: { CARBON_FATAL() << "Cannot use node as type: " << node_id; + } } } +auto LoweringContext::GetLoweredNodeAsType(SemanticsNodeId node_id) + -> llvm::Type* { + if (lowered_nodes_[node_id.index]) { + return lowered_nodes_[node_id.index].get(); + } + + auto* type = BuildLoweredNodeAsType(node_id); + lowered_nodes_[node_id.index] = type; + return type; +} + } // namespace Carbon diff --git a/toolchain/lowering/lowering_context.h b/toolchain/lowering/lowering_context.h index 2b2f2cfe811f5..8003a53d20212 100644 --- a/toolchain/lowering/lowering_context.h +++ b/toolchain/lowering/lowering_context.h @@ -26,8 +26,25 @@ class LoweringContext { // Lowers the SemanticsIR to LLVM IR. auto Run() -> std::unique_ptr; - // Returns a type for the given node. - auto LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type*; + auto HasLoweredNode(SemanticsNodeId node_id) -> bool { + return !lowered_nodes_[node_id.index].isNull(); + } + + // Returns a type for the given node. May construct and cache the type + // if it hasn't yet been built. + auto GetLoweredNodeAsType(SemanticsNodeId node_id) -> llvm::Type*; + + // Returns a value for the given node. + auto GetLoweredNodeAsValue(SemanticsNodeId node_id) -> llvm::Value* { + CARBON_CHECK(lowered_nodes_[node_id.index].is()) + << node_id << ": isNull == " << lowered_nodes_[node_id.index].isNull(); + return lowered_nodes_[node_id.index].get(); + } + // Sets the value for the given node. + auto SetLoweredNodeAsValue(SemanticsNodeId node_id, llvm::Value* value) { + CARBON_CHECK(lowered_nodes_[node_id.index].isNull()) << node_id; + lowered_nodes_[node_id.index] = value; + } auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; } auto llvm_module() -> llvm::Module& { return *llvm_module_; } @@ -37,14 +54,15 @@ class LoweringContext { std::pair>& { return todo_blocks_; } - auto lowered_nodes() -> llvm::SmallVector& { - return lowered_nodes_; - } private: // Runs lowering for a block. auto LowerBlock(SemanticsNodeBlockId block_id) -> void; + // Builds the type for the given node, which should then be cached by the + // caller. + auto BuildLoweredNodeAsType(SemanticsNodeId node_id) -> llvm::Type*; + // State for building the LLVM IR. llvm::LLVMContext* llvm_context_; std::unique_ptr llvm_module_; @@ -60,12 +78,12 @@ class LoweringContext { // Maps nodes in SemanticsIR to a lowered value. This will have one entry per // node, and will be non-null when lowered. It's expected to be sparse during // execution because while expressions will have entries, statements won't. - // TODO: This will probably become a PointerUnion of Value and Type. // TODO: Long-term, we should examine the practical trade-offs of making this // a map; a map may end up lower memory consumption, but a vector offers cache // efficiency and better performance. As a consequence, the right choice is // unclear. - llvm::SmallVector lowered_nodes_; + llvm::SmallVector> + lowered_nodes_; }; // Declare handlers for each SemanticsIR node. diff --git a/toolchain/lowering/lowering_handle.cpp b/toolchain/lowering/lowering_handle.cpp index ff1626e0e9a65..bdc06ffe0e879 100644 --- a/toolchain/lowering/lowering_handle.cpp +++ b/toolchain/lowering/lowering_handle.cpp @@ -18,10 +18,17 @@ auto LoweringHandleCrossReference(LoweringContext& /*context*/, CARBON_FATAL() << "TODO: Add support: " << node; } -auto LoweringHandleAssign(LoweringContext& /*context*/, - SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; +auto LoweringHandleAssign(LoweringContext& context, SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + auto [storage_id, value_id] = node.GetAsAssign(); + if (value_id == SemanticsNodeId::BuiltinEmptyStruct || + value_id == SemanticsNodeId::BuiltinEmptyTuple) { + // Elide the 0-length store; these have no value assigned and it should have + // no effect. + return; + } + context.builder().CreateStore(context.GetLoweredNodeAsValue(value_id), + context.GetLoweredNodeAsValue(storage_id)); } auto LoweringHandleBinaryOperatorAdd(LoweringContext& /*context*/, @@ -31,9 +38,9 @@ auto LoweringHandleBinaryOperatorAdd(LoweringContext& /*context*/, } auto LoweringHandleBindName(LoweringContext& /*context*/, - SemanticsNodeId /*node_id*/, SemanticsNode node) + SemanticsNodeId /*node_id*/, SemanticsNode /*node*/) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + // Probably need to do something here, but not necessary for now. } auto LoweringHandleBuiltin(LoweringContext& /*context*/, @@ -65,11 +72,11 @@ auto LoweringHandleFunctionDeclaration(LoweringContext& context, llvm::SmallVector args; args.resize_for_overwrite(param_refs.size()); for (int i = 0; i < static_cast(param_refs.size()); ++i) { - args[i] = context.LowerNodeToType( + args[i] = context.GetLoweredNodeAsType( context.semantics_ir().GetNode(param_refs[i]).type_id()); } - llvm::Type* return_type = context.LowerNodeToType( + llvm::Type* return_type = context.GetLoweredNodeAsType( callable.return_type_id.is_valid() ? callable.return_type_id : SemanticsNodeId::BuiltinEmptyTuple); llvm::FunctionType* function_type = @@ -108,9 +115,8 @@ auto LoweringHandleIntegerLiteral(LoweringContext& context, -> void { SemanticsIntegerLiteralId int_id = node.GetAsIntegerLiteral(); llvm::APInt i = context.semantics_ir().GetIntegerLiteral(int_id); - llvm::Value* v = llvm::ConstantInt::get(context.builder().getInt32Ty(), - i.getLimitedValue()); - context.lowered_nodes()[node_id.index] = v; + llvm::Value* v = context.builder().getInt32(i.getLimitedValue()); + context.SetLoweredNodeAsValue(node_id, v); } auto LoweringHandleRealLiteral(LoweringContext& /*context*/, @@ -128,7 +134,7 @@ auto LoweringHandleReturnExpression(LoweringContext& context, SemanticsNodeId /*node_id*/, SemanticsNode node) -> void { SemanticsNodeId expr_id = node.GetAsReturnExpression(); - context.builder().CreateRet(context.lowered_nodes()[expr_id.index]); + context.builder().CreateRet(context.GetLoweredNodeAsValue(expr_id)); } auto LoweringHandleStringLiteral(LoweringContext& /*context*/, @@ -137,16 +143,22 @@ auto LoweringHandleStringLiteral(LoweringContext& /*context*/, CARBON_FATAL() << "TODO: Add support: " << node; } -auto LoweringHandleStructMemberAccess(LoweringContext& /*context*/, - SemanticsNodeId /*node_id*/, +auto LoweringHandleStructMemberAccess(LoweringContext& context, + SemanticsNodeId node_id, SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + auto [struct_id, member_index] = node.GetAsStructMemberAccess(); + auto* struct_type = context.GetLoweredNodeAsType( + context.semantics_ir().GetNode(struct_id).type_id()); + auto* gep = context.builder().CreateStructGEP( + struct_type, context.GetLoweredNodeAsValue(struct_id), + member_index.index); + context.SetLoweredNodeAsValue(node_id, gep); } auto LoweringHandleStructType(LoweringContext& /*context*/, - SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + SemanticsNodeId /*node_id*/, + SemanticsNode /*node*/) -> void { + // No action to take. } auto LoweringHandleStructTypeField(LoweringContext& /*context*/, @@ -155,10 +167,22 @@ auto LoweringHandleStructTypeField(LoweringContext& /*context*/, CARBON_FATAL() << "TODO: Add support: " << node; } -auto LoweringHandleStructValue(LoweringContext& /*context*/, - SemanticsNodeId /*node_id*/, SemanticsNode node) +auto LoweringHandleStructValue(LoweringContext& context, + SemanticsNodeId node_id, SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + auto* type = context.GetLoweredNodeAsType(node.type_id()); + auto* alloca = context.builder().CreateAlloca(type); + context.SetLoweredNodeAsValue(node_id, alloca); + + // TODO: Figure out changes to flow so that values are calculated for store. + // Right now, the struct value IR is unevaluated. + // auto refs = + // context.semantics_ir().GetNodeBlock(node.GetAsStructValue().second); + // for (int i = 0; i < static_cast(refs.size()); ++i) { + // auto* gep = context.builder().CreateStructGEP(type, alloca, i); + // context.builder().CreateStore(context.GetLoweredNodeAsValue(refs[i]), + // gep); + // } } auto LoweringHandleStubReference(LoweringContext& /*context*/, @@ -167,10 +191,16 @@ auto LoweringHandleStubReference(LoweringContext& /*context*/, CARBON_FATAL() << "TODO: Add support: " << node; } -auto LoweringHandleVarStorage(LoweringContext& /*context*/, - SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; +auto LoweringHandleVarStorage(LoweringContext& context, SemanticsNodeId node_id, + SemanticsNode node) -> void { + // TODO: This doesn't handle globals. Also, LLVM requires globals to have a + // name. Do we want to generate a name, which would need to be consistent + // across translation units, or use the given name, which requires either + // looking ahead for BindName or restructuring semantics, either of which + // affects the destructuring due to the difference in storage? + auto* alloca = context.builder().CreateAlloca( + context.GetLoweredNodeAsType(node.type_id())); + context.SetLoweredNodeAsValue(node_id, alloca); } } // namespace Carbon diff --git a/toolchain/lowering/testdata/function/definition/params_one.carbon b/toolchain/lowering/testdata/function/definition/params_one.carbon index 74848b730295c..f6d66c184496e 100644 --- a/toolchain/lowering/testdata/function/definition/params_one.carbon +++ b/toolchain/lowering/testdata/function/definition/params_one.carbon @@ -6,7 +6,7 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_one.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_one.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define void @Foo(i32 %a) { +// CHECK:STDOUT: define [0 x i8] @Foo(i32 %a) { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/definition/params_two.carbon b/toolchain/lowering/testdata/function/definition/params_two.carbon index 9b137b9c8dcf0..7d77699c1c960 100644 --- a/toolchain/lowering/testdata/function/definition/params_two.carbon +++ b/toolchain/lowering/testdata/function/definition/params_two.carbon @@ -6,7 +6,7 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_two.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_two.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define void @Foo(i32 %a, i32 %b) { +// CHECK:STDOUT: define [0 x i8] @Foo(i32 %a, i32 %b) { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/definition/params_zero.carbon b/toolchain/lowering/testdata/function/definition/params_zero.carbon index 938e08f2e0375..c185e513de1a0 100644 --- a/toolchain/lowering/testdata/function/definition/params_zero.carbon +++ b/toolchain/lowering/testdata/function/definition/params_zero.carbon @@ -6,7 +6,7 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_zero.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_zero.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define void @Foo() { +// CHECK:STDOUT: define [0 x i8] @Foo() { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/return/no_value.carbon b/toolchain/lowering/testdata/return/no_value.carbon index 8070351b945fb..947da4af71f42 100644 --- a/toolchain/lowering/testdata/return/no_value.carbon +++ b/toolchain/lowering/testdata/return/no_value.carbon @@ -6,7 +6,7 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/return/no_value.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/return/no_value.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define void @Main() { +// CHECK:STDOUT: define [0 x i8] @Main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/struct/empty.carbon b/toolchain/lowering/testdata/struct/empty.carbon new file mode 100644 index 0000000000000..1f803aac0650f --- /dev/null +++ b/toolchain/lowering/testdata/struct/empty.carbon @@ -0,0 +1,21 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/struct/empty.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/struct/empty.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Run() { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca [0 x i8], align 1 +// CHECK:STDOUT: %1 = alloca [0 x i8], align 1 +// CHECK:STDOUT: store ptr %0, ptr %1, align 8 +// CHECK:STDOUT: ret i32 0 +// CHECK:STDOUT: } + +fn Run() -> i32 { + var x: {} = {}; + var y: {} = x; + return 0; +} diff --git a/toolchain/lowering/testdata/struct/member_access.carbon b/toolchain/lowering/testdata/struct/member_access.carbon new file mode 100644 index 0000000000000..855e6199f4a66 --- /dev/null +++ b/toolchain/lowering/testdata/struct/member_access.carbon @@ -0,0 +1,30 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/struct/member_access.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/struct/member_access.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: %0 = type { double, i32 } +// CHECK:STDOUT: %1 = type { double, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Run() { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca %0, align 8 +// CHECK:STDOUT: %1 = alloca %1, align 8 +// CHECK:STDOUT: store ptr %1, ptr %0, align 8 +// CHECK:STDOUT: %2 = alloca i32, align 4 +// CHECK:STDOUT: %3 = getelementptr inbounds %0, ptr %0, i32 0, i32 1 +// CHECK:STDOUT: store ptr %3, ptr %2, align 8 +// CHECK:STDOUT: %4 = alloca i32, align 4 +// CHECK:STDOUT: store ptr %2, ptr %4, align 8 +// CHECK:STDOUT: ret i32 0 +// CHECK:STDOUT: } + +fn Run() -> i32 { + var x: {.a: f64, .b: i32} = {.a = 0.0, .b = 1}; + var y: i32 = x.b; + var z: i32 = y; + return 0; +} diff --git a/toolchain/lowering/testdata/struct/one_entry.carbon b/toolchain/lowering/testdata/struct/one_entry.carbon new file mode 100644 index 0000000000000..85e57b14a46a2 --- /dev/null +++ b/toolchain/lowering/testdata/struct/one_entry.carbon @@ -0,0 +1,27 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/struct/one_entry.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/struct/one_entry.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: %0 = type { i32 } +// CHECK:STDOUT: %1 = type { i32 } +// CHECK:STDOUT: %2 = type { i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Run() { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca %0, align 8 +// CHECK:STDOUT: %1 = alloca %1, align 8 +// CHECK:STDOUT: store ptr %1, ptr %0, align 8 +// CHECK:STDOUT: %2 = alloca %2, align 8 +// CHECK:STDOUT: store ptr %0, ptr %2, align 8 +// CHECK:STDOUT: ret i32 0 +// CHECK:STDOUT: } + +fn Run() -> i32 { + var x: {.a: i32} = {.a = 4}; + var y: {.a: i32} = x; + return 0; +} diff --git a/toolchain/lowering/testdata/struct/two_entries.carbon b/toolchain/lowering/testdata/struct/two_entries.carbon new file mode 100644 index 0000000000000..45b1f2664a332 --- /dev/null +++ b/toolchain/lowering/testdata/struct/two_entries.carbon @@ -0,0 +1,27 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/struct/two_entries.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/struct/two_entries.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: %0 = type { i32, i32 } +// CHECK:STDOUT: %1 = type { i32, i32 } +// CHECK:STDOUT: %2 = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Run() { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca %0, align 8 +// CHECK:STDOUT: %1 = alloca %1, align 8 +// CHECK:STDOUT: store ptr %1, ptr %0, align 8 +// CHECK:STDOUT: %2 = alloca %2, align 8 +// CHECK:STDOUT: store ptr %0, ptr %2, align 8 +// CHECK:STDOUT: ret i32 0 +// CHECK:STDOUT: } + +fn Run() -> i32 { + var x: {.a: i32, .b: i32} = {.a = 1, .b = 2}; + var y: {.a: i32, .b: i32} = x; + return 0; +} diff --git a/toolchain/lowering/testdata/var/local.carbon b/toolchain/lowering/testdata/var/local.carbon new file mode 100644 index 0000000000000..f9a4767da0f73 --- /dev/null +++ b/toolchain/lowering/testdata/var/local.carbon @@ -0,0 +1,19 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/var/local.carbon' +// CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/var/local.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Run() { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca i32, align 4 +// CHECK:STDOUT: store i32 1, ptr %0, align 4 +// CHECK:STDOUT: ret ptr %0 +// CHECK:STDOUT: } + +fn Run() -> i32 { + var x: i32 = 1; + return x; +} From cc4c226a8e9a93fe799c785d3a885c17663839c4 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Fri, 12 May 2023 09:25:03 -0700 Subject: [PATCH 21/29] Update testing/file_test/file_test_base.cpp Co-authored-by: Chandler Carruth --- testing/file_test/file_test_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/file_test/file_test_base.cpp b/testing/file_test/file_test_base.cpp index 30782707ba3db..d2807fb6e3e85 100644 --- a/testing/file_test/file_test_base.cpp +++ b/testing/file_test/file_test_base.cpp @@ -54,7 +54,7 @@ auto FileTestBase::TestBody() -> void { while (std::getline(file_content, line_str)) { ++line_index; llvm::StringRef line = line_str; - line = line.drop_while([](char c) { return c == ' '; }); + line = line.ltrim(); if (!line.consume_front("// CHECK")) { continue; } From 4a9d32bd89982b8014c32d1a2a4bcb43c9df354e Mon Sep 17 00:00:00 2001 From: jonmeow Date: Fri, 12 May 2023 16:34:13 +0000 Subject: [PATCH 22/29] x --- testing/file_test/file_test_base.cpp | 34 ++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/testing/file_test/file_test_base.cpp b/testing/file_test/file_test_base.cpp index d2807fb6e3e85..4b9645f5fbf18 100644 --- a/testing/file_test/file_test_base.cpp +++ b/testing/file_test/file_test_base.cpp @@ -120,21 +120,27 @@ auto FileTestBase::TransformExpectation(int line_index, llvm::StringRef in) break; } case '[': { - static constexpr llvm::StringLiteral LineKeyword = "[[@LINE"; llvm::StringRef line_keyword_cursor = llvm::StringRef(str).substr(pos); - if (line_keyword_cursor.consume_front(LineKeyword)) { - // Allow + or - here; consumeInteger handles -. - line_keyword_cursor.consume_front("+"); - int offset; - // consumeInteger returns true for errors, not false. - CARBON_CHECK(!line_keyword_cursor.consumeInteger(10, offset) && - line_keyword_cursor.consume_front("]]")) - << "Unexpected @LINE offset at `" - << line_keyword_cursor.substr(0, 5) << "` in: " << in; - std::string int_str = llvm::Twine(line_index + offset).str(); - int remove_len = (line_keyword_cursor.data() - str.data()) - pos; - str.replace(pos, remove_len, int_str); - pos += int_str.size(); + if (line_keyword_cursor.consume_front("[[")) { + static constexpr llvm::StringLiteral LineKeyword = "@LINE"; + if (line_keyword_cursor.consume_front(LineKeyword)) { + // Allow + or - here; consumeInteger handles -. + line_keyword_cursor.consume_front("+"); + int offset; + // consumeInteger returns true for errors, not false. + CARBON_CHECK(!line_keyword_cursor.consumeInteger(10, offset) && + line_keyword_cursor.consume_front("]]")) + << "Unexpected @LINE offset at `" + << line_keyword_cursor.substr(0, 5) << "` in: " << in; + std::string int_str = llvm::Twine(line_index + offset).str(); + int remove_len = (line_keyword_cursor.data() - str.data()) - pos; + str.replace(pos, remove_len, int_str); + pos += int_str.size(); + } else { + CARBON_FATAL() << "Unexpected [[, should be {{\\[\\[}} at `" + << line_keyword_cursor.substr(0, 5) + << "` in: " << in; + } } else { // Escape the `[`. str.insert(pos, "\\"); From 7432bf1c41ccb604083fdf0b917097953de6c5a0 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Fri, 12 May 2023 16:52:55 +0000 Subject: [PATCH 23/29] comments --- toolchain/parser/parser_context.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/toolchain/parser/parser_context.h b/toolchain/parser/parser_context.h index fd1ff986192c6..f19be90ec1439 100644 --- a/toolchain/parser/parser_context.h +++ b/toolchain/parser/parser_context.h @@ -18,8 +18,8 @@ namespace Carbon { -// This parser uses a stack for state transitions. See parser_state.def for -// state documentation. +// Context and shared functionality for parser handlers. See parser_state.def +// for state documentation. class ParserContext { public: // Possible operator fixities for errors. @@ -304,6 +304,7 @@ class ParserContext { // The diagnostics below may be emitted a couple different ways as part of // operator parsing. +// TODO: Clean these up, maybe as context functions? CARBON_DIAGNOSTIC( OperatorRequiresParentheses, Error, From eb95e3a52f5b47f50273e4be684143d04155fa32 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Fri, 12 May 2023 17:32:47 +0000 Subject: [PATCH 24/29] x --- toolchain/lowering/lowering_context.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/toolchain/lowering/lowering_context.h b/toolchain/lowering/lowering_context.h index 2b2f2cfe811f5..6f8f81aeb0ce6 100644 --- a/toolchain/lowering/lowering_context.h +++ b/toolchain/lowering/lowering_context.h @@ -13,10 +13,8 @@ namespace Carbon { -// Use LowerToLLVM rather than calling this directly. -// -// This carries state for lowering. `Run()` should only be called once, and -// handles the main execution. +// Context for lowering. `Run()` should only be called once, and handles the +// main execution. class LoweringContext { public: explicit LoweringContext(llvm::LLVMContext& llvm_context, From b53eeecde06b09fc6cf7c60b9fe941216638afeb Mon Sep 17 00:00:00 2001 From: jonmeow Date: Fri, 12 May 2023 17:34:20 +0000 Subject: [PATCH 25/29] comments --- toolchain/semantics/semantics_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/semantics/semantics_context.h b/toolchain/semantics/semantics_context.h index 0957b011c11b0..91010059084b2 100644 --- a/toolchain/semantics/semantics_context.h +++ b/toolchain/semantics/semantics_context.h @@ -16,7 +16,7 @@ namespace Carbon { -// Handles processing of a ParseTree for semantics. +// Context and shared functionality for semantics handlers. class SemanticsContext { public: // Stores references for work. From 4954a78cb2847b6c770e6e1ca36237808222d71c Mon Sep 17 00:00:00 2001 From: jonmeow Date: Fri, 12 May 2023 17:36:11 +0000 Subject: [PATCH 26/29] x --- toolchain/lowering/lowering_context.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/toolchain/lowering/lowering_context.h b/toolchain/lowering/lowering_context.h index 6f8f81aeb0ce6..3589b25b48c88 100644 --- a/toolchain/lowering/lowering_context.h +++ b/toolchain/lowering/lowering_context.h @@ -13,15 +13,15 @@ namespace Carbon { -// Context for lowering. `Run()` should only be called once, and handles the -// main execution. +// Context and shared functionality for lowering handlers. class LoweringContext { public: explicit LoweringContext(llvm::LLVMContext& llvm_context, llvm::StringRef module_name, const SemanticsIR& semantics_ir); - // Lowers the SemanticsIR to LLVM IR. + // Lowers the SemanticsIR to LLVM IR. Should only be called once, and handles + // the main execution loop. auto Run() -> std::unique_ptr; // Returns a type for the given node. From 52e08558f58e2c1a693016d0541585b4a6aba162 Mon Sep 17 00:00:00 2001 From: jonmeow Date: Tue, 16 May 2023 17:20:50 +0000 Subject: [PATCH 27/29] x --- toolchain/lowering/lowering_context.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp index 08a0d7e3e4342..450db47548c98 100644 --- a/toolchain/lowering/lowering_context.cpp +++ b/toolchain/lowering/lowering_context.cpp @@ -55,6 +55,10 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id) case SemanticsBuiltinKind::EmptyTuple.AsInt(): case SemanticsBuiltinKind::EmptyTupleType.AsInt(): // Represent empty data as 0-length arrays. + // TODO: Investigate special-casing handling of these so that they can be + // collectively replaced with LLVM's void, particularly around function + // returns. LLVM doesn't allow declaring variables with a void type, so + // that may require significant special casing. // TODO: Work to remove EmptyTuple here. return llvm::ArrayType::get(builder_.getInt8Ty(), 0); case SemanticsBuiltinKind::FloatingPointType.AsInt(): From 5c5369d7b068ee959db5c160b1bd7a1d83feb79f Mon Sep 17 00:00:00 2001 From: jonmeow Date: Wed, 17 May 2023 16:57:03 +0000 Subject: [PATCH 28/29] struct --- toolchain/lowering/lowering_context.cpp | 7 +++---- .../testdata/function/definition/params_one.carbon | 4 +++- .../testdata/function/definition/params_two.carbon | 4 +++- .../testdata/function/definition/params_zero.carbon | 4 +++- toolchain/lowering/testdata/return/no_value.carbon | 4 +++- toolchain/lowering/testdata/struct/empty.carbon | 6 ++++-- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp index 450db47548c98..da536b3723da7 100644 --- a/toolchain/lowering/lowering_context.cpp +++ b/toolchain/lowering/lowering_context.cpp @@ -60,7 +60,8 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id) // returns. LLVM doesn't allow declaring variables with a void type, so // that may require significant special casing. // TODO: Work to remove EmptyTuple here. - return llvm::ArrayType::get(builder_.getInt8Ty(), 0); + return llvm::StructType::create(*llvm_context_, + llvm::ArrayRef()); case SemanticsBuiltinKind::FloatingPointType.AsInt(): // TODO: Handle different sizes. return builder_.getDoubleTy(); @@ -83,9 +84,7 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id) << type_id; subtypes.push_back(GetLoweredNodeAsType(type_id)); } - auto* type = llvm::StructType::create(*llvm_context_, subtypes); - lowered_nodes_[node_id.index] = type; - return type; + return llvm::StructType::create(*llvm_context_, subtypes); } default: { CARBON_FATAL() << "Cannot use node as type: " << node_id; diff --git a/toolchain/lowering/testdata/function/definition/params_one.carbon b/toolchain/lowering/testdata/function/definition/params_one.carbon index f6d66c184496e..a3ed4233f9e0d 100644 --- a/toolchain/lowering/testdata/function/definition/params_one.carbon +++ b/toolchain/lowering/testdata/function/definition/params_one.carbon @@ -6,7 +6,9 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_one.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_one.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define [0 x i8] @Foo(i32 %a) { +// CHECK:STDOUT: %0 = type {} +// CHECK:STDOUT: +// CHECK:STDOUT: define %0 @Foo(i32 %a) { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/definition/params_two.carbon b/toolchain/lowering/testdata/function/definition/params_two.carbon index 7d77699c1c960..f284c112e7da0 100644 --- a/toolchain/lowering/testdata/function/definition/params_two.carbon +++ b/toolchain/lowering/testdata/function/definition/params_two.carbon @@ -6,7 +6,9 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_two.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_two.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define [0 x i8] @Foo(i32 %a, i32 %b) { +// CHECK:STDOUT: %0 = type {} +// CHECK:STDOUT: +// CHECK:STDOUT: define %0 @Foo(i32 %a, i32 %b) { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/definition/params_zero.carbon b/toolchain/lowering/testdata/function/definition/params_zero.carbon index c185e513de1a0..dbc40f376e2aa 100644 --- a/toolchain/lowering/testdata/function/definition/params_zero.carbon +++ b/toolchain/lowering/testdata/function/definition/params_zero.carbon @@ -6,7 +6,9 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/function/definition/params_zero.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/function/definition/params_zero.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define [0 x i8] @Foo() { +// CHECK:STDOUT: %0 = type {} +// CHECK:STDOUT: +// CHECK:STDOUT: define %0 @Foo() { // CHECK:STDOUT: entry: // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/return/no_value.carbon b/toolchain/lowering/testdata/return/no_value.carbon index 947da4af71f42..e5be729f8565b 100644 --- a/toolchain/lowering/testdata/return/no_value.carbon +++ b/toolchain/lowering/testdata/return/no_value.carbon @@ -6,7 +6,9 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/return/no_value.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/return/no_value.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: define [0 x i8] @Main() { +// CHECK:STDOUT: %0 = type {} +// CHECK:STDOUT: +// CHECK:STDOUT: define %0 @Main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/struct/empty.carbon b/toolchain/lowering/testdata/struct/empty.carbon index 1f803aac0650f..303234ecd4f98 100644 --- a/toolchain/lowering/testdata/struct/empty.carbon +++ b/toolchain/lowering/testdata/struct/empty.carbon @@ -6,10 +6,12 @@ // CHECK:STDOUT: ; ModuleID = 'toolchain/lowering/testdata/struct/empty.carbon' // CHECK:STDOUT: source_filename = "toolchain/lowering/testdata/struct/empty.carbon" // CHECK:STDOUT: +// CHECK:STDOUT: %0 = type {} +// CHECK:STDOUT: // CHECK:STDOUT: define i32 @Run() { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %0 = alloca [0 x i8], align 1 -// CHECK:STDOUT: %1 = alloca [0 x i8], align 1 +// CHECK:STDOUT: %0 = alloca %0, align 8 +// CHECK:STDOUT: %1 = alloca %0, align 8 // CHECK:STDOUT: store ptr %0, ptr %1, align 8 // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } From ef8520e2c0cd730cdea11f4bfdd57164dd7b143d Mon Sep 17 00:00:00 2001 From: jonmeow Date: Wed, 17 May 2023 20:46:07 +0000 Subject: [PATCH 29/29] comment --- toolchain/lowering/lowering_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp index da536b3723da7..f0c92eb037aa0 100644 --- a/toolchain/lowering/lowering_context.cpp +++ b/toolchain/lowering/lowering_context.cpp @@ -54,7 +54,7 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id) case SemanticsBuiltinKind::EmptyStructType.AsInt(): case SemanticsBuiltinKind::EmptyTuple.AsInt(): case SemanticsBuiltinKind::EmptyTupleType.AsInt(): - // Represent empty data as 0-length arrays. + // Represent empty types as empty structs. // TODO: Investigate special-casing handling of these so that they can be // collectively replaced with LLVM's void, particularly around function // returns. LLVM doesn't allow declaring variables with a void type, so