From bb521fdd5bc44a1aa38370a90bc11c53e24fc483 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Thu, 13 Oct 2022 15:54:37 -0700 Subject: [PATCH] Switch the parse tree tests to lit (#2289) This switch is being done in order to make it easier to update tests when the parse tree structure changes. I've been spending a lot of time doing such updates as part of refactoring the parse tree, and I expect more, so that's really at the root of all the refactoring I've been doing to lit updates. --- toolchain/parser/BUILD | 15 - toolchain/parser/__init__.py | 0 toolchain/parser/lit_autoupdate.py | 37 + toolchain/parser/parse_test_helpers.h | 346 ----- toolchain/parser/parse_tree_test.cpp | 1288 ----------------- toolchain/parser/testdata/BUILD | 16 + toolchain/parser/testdata/basics/empty.carbon | 9 + .../testdata/basics/empty_declaration.carbon | 12 + .../testdata/basics/function_call.carbon | 39 + .../basics/invalid_designators.carbon | 35 + .../testdata/basics/no_intro_with_semi.carbon | 13 + .../basics/no_intro_without_semi.carbon | 12 + .../parser/testdata/basics/package.carbon | 35 + .../basics/paren_match_regression.carbon | 19 + .../parser/testdata/basics/return.carbon | 47 + .../parser/testdata/basics/structs.carbon | 69 + .../parser/testdata/basics/tuples.carbon | 42 + toolchain/parser/testdata/basics/var.carbon | 41 + .../testdata/for/colon_instead_of_in.carbon | 37 + .../parser/testdata/for/missing_in.carbon | 36 + .../parser/testdata/for/missing_var.carbon | 34 + toolchain/parser/testdata/for/nested.carbon | 50 + toolchain/parser/testdata/for/simple.carbon | 37 + .../function/declaration/basic.carbon | 16 + .../identifier_instead_of_sig.carbon | 15 + .../function/declaration/missing_name.carbon | 14 + .../declaration/no_sig_or_semi.carbon | 14 + .../declaration/only_fn_and_semi.carbon | 14 + .../declaration/repeated_fn_and_semi.carbon | 14 + ...skip_indented_newline_until_outdent.carbon | 21 + .../skip_indented_newline_with_semi.carbon | 22 + .../skip_indented_newline_without_semi.carbon | 21 + .../skip_to_newline_without_semi.carbon | 19 + .../skip_without_semi_to_curly.carbon | 18 + .../with_identifier_as_param.carbon | 17 + .../function/declaration/with_params.carbon | 23 + .../declaration/with_return_type.carbon | 18 + ...hout_name_and_many_tokens_in_params.carbon | 14 + .../testdata/function/definition/basic.carbon | 18 + .../identifier_in_statements.carbon | 23 + .../function/definition/with_params.carbon | 35 + .../definition/with_return_type.carbon | 24 + toolchain/parser/testdata/if/basic.carbon | 45 + toolchain/parser/testdata/if/else.carbon | 85 ++ .../parser/testdata/if/else_unbraced.carbon | 79 + toolchain/parser/testdata/if/errors.carbon | 46 + toolchain/parser/testdata/if/unbraced.carbon | 40 + toolchain/parser/testdata/lit.cfg.py | 1 + .../testdata/operators/associative.carbon | 25 + .../parser/testdata/operators/fixity.carbon | 84 ++ .../missing_precedence_and_or.carbon | 26 + .../operators/missing_precedence_not.carbon | 31 + .../missing_precedence_or_and.carbon | 26 + .../testdata/operators/postfix_unary.carbon | 23 + .../testdata/operators/prefix_unary.carbon | 23 + .../parser/testdata/operators/variety.carbon | 44 + toolchain/parser/testdata/while/basic.carbon | 48 + .../parser/testdata/while/unbraced.carbon | 28 + 58 files changed, 1634 insertions(+), 1649 deletions(-) create mode 100644 toolchain/parser/__init__.py create mode 100755 toolchain/parser/lit_autoupdate.py delete mode 100644 toolchain/parser/parse_test_helpers.h create mode 100644 toolchain/parser/testdata/BUILD create mode 100644 toolchain/parser/testdata/basics/empty.carbon create mode 100644 toolchain/parser/testdata/basics/empty_declaration.carbon create mode 100644 toolchain/parser/testdata/basics/function_call.carbon create mode 100644 toolchain/parser/testdata/basics/invalid_designators.carbon create mode 100644 toolchain/parser/testdata/basics/no_intro_with_semi.carbon create mode 100644 toolchain/parser/testdata/basics/no_intro_without_semi.carbon create mode 100644 toolchain/parser/testdata/basics/package.carbon create mode 100644 toolchain/parser/testdata/basics/paren_match_regression.carbon create mode 100644 toolchain/parser/testdata/basics/return.carbon create mode 100644 toolchain/parser/testdata/basics/structs.carbon create mode 100644 toolchain/parser/testdata/basics/tuples.carbon create mode 100644 toolchain/parser/testdata/basics/var.carbon create mode 100644 toolchain/parser/testdata/for/colon_instead_of_in.carbon create mode 100644 toolchain/parser/testdata/for/missing_in.carbon create mode 100644 toolchain/parser/testdata/for/missing_var.carbon create mode 100644 toolchain/parser/testdata/for/nested.carbon create mode 100644 toolchain/parser/testdata/for/simple.carbon create mode 100644 toolchain/parser/testdata/function/declaration/basic.carbon create mode 100644 toolchain/parser/testdata/function/declaration/identifier_instead_of_sig.carbon create mode 100644 toolchain/parser/testdata/function/declaration/missing_name.carbon create mode 100644 toolchain/parser/testdata/function/declaration/no_sig_or_semi.carbon create mode 100644 toolchain/parser/testdata/function/declaration/only_fn_and_semi.carbon create mode 100644 toolchain/parser/testdata/function/declaration/repeated_fn_and_semi.carbon create mode 100644 toolchain/parser/testdata/function/declaration/skip_indented_newline_until_outdent.carbon create mode 100644 toolchain/parser/testdata/function/declaration/skip_indented_newline_with_semi.carbon create mode 100644 toolchain/parser/testdata/function/declaration/skip_indented_newline_without_semi.carbon create mode 100644 toolchain/parser/testdata/function/declaration/skip_to_newline_without_semi.carbon create mode 100644 toolchain/parser/testdata/function/declaration/skip_without_semi_to_curly.carbon create mode 100644 toolchain/parser/testdata/function/declaration/with_identifier_as_param.carbon create mode 100644 toolchain/parser/testdata/function/declaration/with_params.carbon create mode 100644 toolchain/parser/testdata/function/declaration/with_return_type.carbon create mode 100644 toolchain/parser/testdata/function/declaration/without_name_and_many_tokens_in_params.carbon create mode 100644 toolchain/parser/testdata/function/definition/basic.carbon create mode 100644 toolchain/parser/testdata/function/definition/identifier_in_statements.carbon create mode 100644 toolchain/parser/testdata/function/definition/with_params.carbon create mode 100644 toolchain/parser/testdata/function/definition/with_return_type.carbon create mode 100644 toolchain/parser/testdata/if/basic.carbon create mode 100644 toolchain/parser/testdata/if/else.carbon create mode 100644 toolchain/parser/testdata/if/else_unbraced.carbon create mode 100644 toolchain/parser/testdata/if/errors.carbon create mode 100644 toolchain/parser/testdata/if/unbraced.carbon create mode 120000 toolchain/parser/testdata/lit.cfg.py create mode 100644 toolchain/parser/testdata/operators/associative.carbon create mode 100644 toolchain/parser/testdata/operators/fixity.carbon create mode 100644 toolchain/parser/testdata/operators/missing_precedence_and_or.carbon create mode 100644 toolchain/parser/testdata/operators/missing_precedence_not.carbon create mode 100644 toolchain/parser/testdata/operators/missing_precedence_or_and.carbon create mode 100644 toolchain/parser/testdata/operators/postfix_unary.carbon create mode 100644 toolchain/parser/testdata/operators/prefix_unary.carbon create mode 100644 toolchain/parser/testdata/operators/variety.carbon create mode 100644 toolchain/parser/testdata/while/basic.carbon create mode 100644 toolchain/parser/testdata/while/unbraced.carbon diff --git a/toolchain/parser/BUILD b/toolchain/parser/BUILD index 6ff6acd55dc4..dd6fbffd0cd8 100644 --- a/toolchain/parser/BUILD +++ b/toolchain/parser/BUILD @@ -49,27 +49,12 @@ cc_library( ], ) -cc_library( - name = "parse_test_helpers", - testonly = 1, - hdrs = ["parse_test_helpers.h"], - deps = [ - ":parse_node_kind", - ":parse_tree", - "//common:check", - "//toolchain/lexer:tokenized_buffer", - "@com_google_googletest//:gtest", - "@llvm-project//llvm:Support", - ], -) - cc_test( name = "parse_tree_test", size = "small", srcs = ["parse_tree_test.cpp"], deps = [ ":parse_node_kind", - ":parse_test_helpers", ":parse_tree", "//common:gtest_main", "//common:ostream", diff --git a/toolchain/parser/__init__.py b/toolchain/parser/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/toolchain/parser/lit_autoupdate.py b/toolchain/parser/lit_autoupdate.py new file mode 100755 index 000000000000..b24ad2f9d2bb --- /dev/null +++ b/toolchain/parser/lit_autoupdate.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +"""Updates the CHECK: lines in lit tests based on the AUTOUPDATE line.""" + +__copyright__ = """ +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 +""" + +import os +import sys +from pathlib import Path + + +def main() -> None: + # Calls the main script with explorer settings. This uses execv in order to + # avoid Python import behaviors. + this_py = Path(__file__).resolve() + actual_py = this_py.parent.parent.parent.joinpath( + "bazel", "testing", "lit_autoupdate_base.py" + ) + args = [ + sys.argv[0], + # Flags to configure for explorer testing. + "--build_target", + "//toolchain/driver:carbon", + "--line_number_pattern", + r"(?<=\.carbon:)(\d+)(?=(?:\D|$))", + "--testdata", + "toolchain/parser/testdata", + ] + sys.argv[1:] + os.execv(actual_py, args) + + +if __name__ == "__main__": + main() diff --git a/toolchain/parser/parse_test_helpers.h b/toolchain/parser/parse_test_helpers.h deleted file mode 100644 index 3b922cf79b29..000000000000 --- a/toolchain/parser/parse_test_helpers.h +++ /dev/null @@ -1,346 +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_PARSE_TEST_HELPERS_H_ -#define CARBON_TOOLCHAIN_PARSER_PARSE_TEST_HELPERS_H_ - -#include - -#include -#include -#include -#include - -#include "common/check.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "toolchain/lexer/tokenized_buffer.h" -#include "toolchain/parser/parse_node_kind.h" -#include "toolchain/parser/parse_tree.h" - -namespace Carbon { - -// Enable printing a parse tree from Google Mock. -inline void PrintTo(const ParseTree& tree, std::ostream* output) { - std::string text; - llvm::raw_string_ostream text_stream(text); - tree.Print(text_stream); - *output << "\n" << text_stream.str() << "\n"; -} - -namespace Testing { - -// An aggregate used to describe an expected parse tree. -// -// This type is designed to be used via aggregate initialization with designated -// initializers. The latter make it easy to default everything and then override -// the desired aspects when writing an expectation in a test. -struct ExpectedNode { - ParseNodeKind kind = ParseNodeKind::EmptyDeclaration(); - std::string text; - bool has_error = false; - bool skip_subtree = false; - std::vector children; -}; - -// Implementation of a matcher for a parse tree based on a tree of expected -// nodes. -// -// Don't create this directly, instead use `MatchParseTreeNodes` to construct a -// matcher based on this. -class ExpectedNodesMatcher - : public ::testing::MatcherInterface { - public: - explicit ExpectedNodesMatcher( - llvm::SmallVector expected_nodess) - : expected_nodes_(std::move(expected_nodess)) {} - - auto MatchAndExplain(const ParseTree& tree, - ::testing::MatchResultListener* output_ptr) const - -> bool override; - auto DescribeTo(std::ostream* output_ptr) const -> void override; - - private: - auto MatchExpectedNode(const ParseTree& tree, ParseTree::Node n, - int postorder_index, const ExpectedNode& expected_node, - ::testing::MatchResultListener& output) const -> bool; - - llvm::SmallVector expected_nodes_; -}; - -// Implementation of the Google Mock interface for matching (and explaining any -// failure). -inline auto ExpectedNodesMatcher::MatchAndExplain( - const ParseTree& tree, ::testing::MatchResultListener* output_ptr) const - -> bool { - auto& output = *output_ptr; - bool matches = true; - const auto rpo = llvm::reverse(tree.postorder()); - const auto nodes_begin = rpo.begin(); - const auto nodes_end = rpo.end(); - auto nodes_it = nodes_begin; - llvm::SmallVector expected_node_stack; - for (const ExpectedNode& en : expected_nodes_) { - expected_node_stack.push_back(&en); - } - while (!expected_node_stack.empty()) { - if (nodes_it == nodes_end) { - // We'll check the size outside the loop. - break; - } - - ParseTree::Node n = *nodes_it++; - int postorder_index = n.index(); - - const ExpectedNode& expected_node = *expected_node_stack.pop_back_val(); - - if (!MatchExpectedNode(tree, n, postorder_index, expected_node, output)) { - matches = false; - } - - if (expected_node.skip_subtree) { - CARBON_CHECK(expected_node.children.empty()) - << "Must not skip an expected subtree while specifying expected " - "children!"; - nodes_it = llvm::reverse(tree.postorder(n)).end(); - continue; - } - - // We want to make sure we don't end up with unsynchronized walks, so skip - // ahead in the tree to ensure that the number of children of this node and - // the expected number of children match. - int num_children = - std::distance(tree.children(n).begin(), tree.children(n).end()); - if (num_children != static_cast(expected_node.children.size())) { - output - << "\nParse node (postorder index #" << postorder_index << ") has " - << num_children << " children, expected " - << expected_node.children.size() - << ". Skipping this subtree to avoid any unsynchronized tree walk."; - matches = false; - nodes_it = llvm::reverse(tree.postorder(n)).end(); - continue; - } - - // Push the children onto the stack to continue matching. The expectation - // is in preorder, but we visit the parse tree in reverse postorder. This - // causes the siblings to be visited in reverse order from the expected - // list. However, we use a stack which inherently does this reverse for us - // so we simply append to the stack here. - for (const ExpectedNode& child_expected_node : expected_node.children) { - expected_node_stack.push_back(&child_expected_node); - } - } - - // We don't directly check the size because we allow expectations to skip - // subtrees. Instead, we need to check that we successfully processed all of - // the actual tree and consumed all of the expected tree. - if (nodes_it != nodes_end) { - CARBON_CHECK(expected_node_stack.empty()) - << "If we have unmatched nodes in the input tree, should only finish " - "having fully processed expected tree."; - output << "\nFinished processing expected nodes and there are still " - << (nodes_end - nodes_it) << " unexpected nodes."; - matches = false; - } else if (!expected_node_stack.empty()) { - output << "\nProcessed all " << (nodes_end - nodes_begin) - << " nodes and still have " << expected_node_stack.size() - << " expected nodes that were unmatched."; - matches = false; - } - - return matches; -} - -// Implementation of the Google Mock interface for describing the expected node -// tree. -// -// This is designed to describe the expected tree node structure in as similar -// of a format to the parse tree's print format as is reasonable. There is both -// more and less information, so it won't be exact, but should be close enough -// to make it easy to visually compare the two. -inline auto ExpectedNodesMatcher::DescribeTo(std::ostream* output_ptr) const - -> void { - auto& output = *output_ptr; - output << "Matches expected node pattern:\n[\n"; - - // We want to walk these in RPO instead of in preorder to match the printing - // of the actual parse tree. - llvm::SmallVector, 16> - expected_node_stack; - for (const ExpectedNode& expected_node : llvm::reverse(expected_nodes_)) { - expected_node_stack.push_back({&expected_node, 0}); - } - - while (!expected_node_stack.empty()) { - const ExpectedNode& expected_node = *expected_node_stack.back().first; - int depth = expected_node_stack.back().second; - expected_node_stack.pop_back(); - for (int indent_count = 0; indent_count < depth; ++indent_count) { - output << " "; - } - output << "{kind: '" << expected_node.kind.name().str() << "'"; - if (!expected_node.text.empty()) { - output << ", text: '" << expected_node.text << "'"; - } - if (expected_node.has_error) { - output << ", has_error: yes"; - } - if (expected_node.skip_subtree) { - output << ", skip_subtree: yes"; - } - - if (!expected_node.children.empty()) { - CARBON_CHECK(!expected_node.skip_subtree) - << "Must not have children and skip a subtree!"; - output << ", children: [\n"; - for (const ExpectedNode& child_expected_node : - llvm::reverse(expected_node.children)) { - expected_node_stack.push_back({&child_expected_node, depth + 1}); - } - // If we have children, we know we're not popping off. - continue; - } - - // If this is some form of leaf we'll at least need to close it. It may also - // be the last sibling of its parent, and we'll need to close any parents as - // we pop up. - output << "}"; - if (!expected_node_stack.empty()) { - CARBON_CHECK(depth >= expected_node_stack.back().second) - << "Cannot have an increase in depth on a leaf node!"; - // The distance we need to pop is the difference in depth. - int pop_depth = depth - expected_node_stack.back().second; - for (int pop_count = 0; pop_count < pop_depth; ++pop_count) { - // Close both the children array and the node mapping. - output << "]}"; - } - } - output << "\n"; - } - output << "]\n"; -} - -inline auto ExpectedNodesMatcher::MatchExpectedNode( - const ParseTree& tree, ParseTree::Node n, int postorder_index, - const ExpectedNode& expected_node, - ::testing::MatchResultListener& output) const -> bool { - bool matches = true; - - ParseNodeKind kind = tree.node_kind(n); - if (kind != expected_node.kind) { - output << "\nParse node (postorder index #" << postorder_index << ") is a " - << kind.name().str() << ", expected a " - << expected_node.kind.name().str() << "."; - matches = false; - } - - if (tree.node_has_error(n) != expected_node.has_error) { - output << "\nParse node (postorder index #" << postorder_index << ") " - << (tree.node_has_error(n) ? "has an error" - : "does not have an error") - << ", expected that it " - << (expected_node.has_error ? "has an error" - : "does not have an error") - << "."; - matches = false; - } - - llvm::StringRef node_text = tree.GetNodeText(n); - if (!expected_node.text.empty() && node_text != expected_node.text) { - output << "\nParse node (postorder index #" << postorder_index - << ") is spelled '" << node_text.str() << "', expected '" - << expected_node.text << "'."; - matches = false; - } - - return matches; -} - -// Creates a matcher for a parse tree using a tree of expected nodes. -// -// This is intended to be used with an braced initializer list style aggregate -// initializer for an argument, allowing it to describe a tree structure via -// nested `ExpectedNode` objects. -inline auto MatchParseTreeNodes( - llvm::SmallVector expected_nodes) - -> ::testing::Matcher { - return ::testing::MakeMatcher( - new ExpectedNodesMatcher(std::move(expected_nodes))); -} - -// Matcher argument for a node with errors. -struct HasErrorTag {}; -inline constexpr HasErrorTag HasError; - -// Matcher argument to skip checking the children of a node. -struct AnyChildrenTag {}; -inline constexpr AnyChildrenTag AnyChildren; - -// A function to generate ExpectedNodes a little more tersely and readably. The -// meaning of each argument is inferred from its type. -template -auto MatchNode(Args... args) -> ExpectedNode { - struct ArgHandler { - ExpectedNode expected; - void UpdateExpectationsForArg(ParseNodeKind kind) { expected.kind = kind; } - void UpdateExpectationsForArg(std::string text) { - expected.text = std::move(text); - } - void UpdateExpectationsForArg(HasErrorTag /*tag*/) { - expected.has_error = true; - } - void UpdateExpectationsForArg(AnyChildrenTag /*tag*/) { - expected.skip_subtree = true; - } - void UpdateExpectationsForArg(ExpectedNode node) { - expected.children.push_back(std::move(node)); - } - }; - ArgHandler handler; - (handler.UpdateExpectationsForArg(args), ...); - return handler.expected; -} - -// A MatchFoo function for each parse node Foo. Used to construct ExpectedNodes -// for use in MatchParseTreeNodes. Example: -// -// MatchParseTreeNodes( -// {MatchFunctionDeclaration("fn", MatchIdentifier("F"), -// MatchParameterList(MatchParameterListEnd()), -// MatchDeclarationEnd(";")), -// MatchFileEnd()}); -#define CARBON_PARSE_NODE_KIND(kind) \ - template \ - auto Match##kind(Args... args)->ExpectedNode { \ - return MatchNode(ParseNodeKind::kind(), std::move(args)...); \ - } -#include "toolchain/parser/parse_node_kind.def" - -// Helper for matching a designator `lhs.rhs`. -inline auto MatchDesignator(ExpectedNode lhs, std::string rhs) -> ExpectedNode { - return MatchDesignatorExpression(std::move(lhs), - MatchDesignatedName(std::move(rhs))); -} - -// Helper for matching a function parameter list. -template -auto MatchParameters(Args... args) -> ExpectedNode { - return MatchParameterList("(", std::move(args)..., MatchParameterListEnd()); -} - -// Helper for matching the statements in the body of a simple function -// definition with no parameters. -template -auto MatchFunctionWithBody(Args... args) -> ExpectedNode { - return MatchFunctionDeclaration( - MatchDeclaredName(), MatchParameters(), - MatchCodeBlock(std::move(args)..., MatchCodeBlockEnd())); -} - -} // namespace Testing -} // namespace Carbon - -#endif // CARBON_TOOLCHAIN_PARSER_PARSE_TEST_HELPERS_H_ diff --git a/toolchain/parser/parse_tree_test.cpp b/toolchain/parser/parse_tree_test.cpp index e1bf4f40ae07..a23868933352 100644 --- a/toolchain/parser/parse_tree_test.cpp +++ b/toolchain/parser/parse_tree_test.cpp @@ -9,16 +9,11 @@ #include -#include "common/ostream.h" -#include "llvm/ADT/Sequence.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/SourceMgr.h" #include "toolchain/common/yaml_test_helpers.h" #include "toolchain/diagnostics/diagnostic_emitter.h" #include "toolchain/diagnostics/mocks.h" #include "toolchain/lexer/tokenized_buffer.h" -#include "toolchain/parser/parse_node_kind.h" -#include "toolchain/parser/parse_test_helpers.h" namespace Carbon::Testing { namespace { @@ -26,8 +21,6 @@ namespace { using ::testing::AtLeast; using ::testing::ElementsAre; using ::testing::Eq; -using ::testing::Ne; -using ::testing::StrEq; class ParseTreeTest : public ::testing::Test { protected: @@ -59,589 +52,6 @@ TEST_F(ParseTreeTest, IsValid) { EXPECT_TRUE((*tree.postorder().begin()).is_valid()); } -TEST_F(ParseTreeTest, Empty) { - TokenizedBuffer tokens = GetTokenizedBuffer(""); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, EmptyDeclaration) { - TokenizedBuffer tokens = GetTokenizedBuffer(";"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - auto it = tree.postorder().begin(); - auto end = tree.postorder().end(); - ASSERT_THAT(it, Ne(end)); - ParseTree::Node n = *it++; - ASSERT_THAT(it, Ne(end)); - ParseTree::Node eof = *it++; - EXPECT_THAT(it, Eq(end)); - - // Directly test the main API so that we get easier to understand errors in - // simple cases than what the custom matcher will produce. - EXPECT_FALSE(tree.node_has_error(n)); - EXPECT_FALSE(tree.node_has_error(eof)); - EXPECT_THAT(tree.node_kind(n), Eq(ParseNodeKind::EmptyDeclaration())); - EXPECT_THAT(tree.node_kind(eof), Eq(ParseNodeKind::FileEnd())); - - auto t = tree.node_token(n); - ASSERT_THAT(tokens.tokens().begin(), Ne(tokens.tokens().end())); - EXPECT_THAT(t, Eq(*tokens.tokens().begin())); - EXPECT_THAT(tokens.GetTokenText(t), Eq(";")); - - EXPECT_THAT(tree.children(n).begin(), Eq(tree.children(n).end())); - EXPECT_THAT(tree.children(eof).begin(), Eq(tree.children(eof).end())); - - EXPECT_THAT(tree.postorder().begin(), Eq(tree.postorder(n).begin())); - EXPECT_THAT(tree.postorder(n).end(), Eq(tree.postorder(eof).begin())); - EXPECT_THAT(tree.postorder(eof).end(), Eq(tree.postorder().end())); -} - -TEST_F(ParseTreeTest, BasicFunctionDeclaration) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes( - {MatchFunctionDeclaration("fn", MatchDeclaredName("F"), - MatchParameters(), - MatchDeclarationEnd(";")), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, NoDeclarationIntroducerOrSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer("foo bar baz"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, NoDeclarationIntroducerWithSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer("foo;"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchEmptyDeclaration(";", HasError), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, JustFunctionIntroducerAndSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn;"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFunctionDeclaration( - HasError, MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, RepeatedFunctionIntroducerAndSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn fn;"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFunctionDeclaration( - HasError, MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationWithNoSignatureOrSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn foo"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration(HasError, MatchDeclaredName("foo")), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, - FunctionDeclarationWithIdentifierInsteadOfSignatureAndSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn foo bar;"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFunctionDeclaration( - HasError, MatchDeclaredName("foo"), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationWithParameterList) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn foo(bar: i32, baz: i32);"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), - MatchParameterList(MatchPatternBinding(MatchDeclaredName("bar"), - ":", MatchLiteral("i32")), - MatchParameterListComma(), - MatchPatternBinding(MatchDeclaredName("baz"), - ":", MatchLiteral("i32")), - MatchParameterListEnd()), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDefinitionWithParameterList) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn foo(bar: i64, baz: i64) {\n" - " foo(baz, bar + baz);\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), - MatchParameterList(MatchPatternBinding(MatchDeclaredName("bar"), - ":", MatchLiteral("i64")), - MatchParameterListComma(), - MatchPatternBinding(MatchDeclaredName("baz"), - ":", MatchLiteral("i64")), - MatchParameterListEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("foo"), MatchNameReference("baz"), - MatchCallExpressionComma(), - MatchInfixOperator(MatchNameReference("bar"), "+", - MatchNameReference("baz")), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationWithReturnType) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn foo() -> u32;"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration(MatchDeclaredName("foo"), MatchParameters(), - MatchReturnType(MatchLiteral("u32")), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDefinitionWithReturnType) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn foo() -> f64 {\n" - " return 42;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT(tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), MatchParameters(), - MatchReturnType(MatchLiteral("f64")), - MatchCodeBlock(MatchReturnStatement(MatchLiteral("42"), - MatchStatementEnd()), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationWithSingleIdentifierParameterList) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn foo(bar);"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - // Note: this might become valid depending on the parameter syntax, this test - // shouldn't be taken as a sign it should remain invalid. - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), - MatchParameterList(HasError, MatchParameterListEnd()), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationWithoutName) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn ();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFunctionDeclaration( - HasError, MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, - FunctionDeclarationWithoutNameAndManyTokensToSkipInGroupedSymbols) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "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);"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes({MatchFunctionDeclaration( - HasError, MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationSkipToNewlineWithoutSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn ()\n" - "fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT( - tree, MatchParseTreeNodes({MatchFunctionDeclaration(HasError), - MatchFunctionDeclaration( - MatchDeclaredName("F"), MatchParameters(), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationSkipIndentedNewlineWithSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn (x,\n" - " y,\n" - " z);\n" - "fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration(HasError, MatchDeclarationEnd()), - MatchFunctionDeclaration(MatchDeclaredName("F"), MatchParameters(), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationSkipIndentedNewlineWithoutSemi) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn (x,\n" - " y,\n" - " z)\n" - "fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT( - tree, MatchParseTreeNodes({MatchFunctionDeclaration(HasError), - MatchFunctionDeclaration( - MatchDeclaredName("F"), MatchParameters(), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationSkipIndentedNewlineUntilOutdent) { - TokenizedBuffer tokens = GetTokenizedBuffer( - " fn (x,\n" - " y,\n" - " z)\n" - "fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT( - tree, MatchParseTreeNodes({MatchFunctionDeclaration(HasError), - MatchFunctionDeclaration( - MatchDeclaredName("F"), MatchParameters(), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDeclarationSkipWithoutSemiToCurly) { - // TODO: We don't have a grammar construct that uses curlies yet so this just - // won't parse at all. Once it does, we should ensure that the close brace - // gets properly parsed for the struct (or whatever other curly-braced syntax - // we have grouping function declarations) despite the invalid function - // declaration missing a semicolon. - TokenizedBuffer tokens = GetTokenizedBuffer( - "struct X { fn () }\n" - "fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); -} - -TEST_F(ParseTreeTest, BasicFunctionDefinition) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("F"), MatchParameters(), - MatchCodeBlock("{", MatchCodeBlockEnd("}"))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDefinitionWithIdentifierInStatements) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " bar\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - // Note: this might become valid depending on the expression syntax. This test - // shouldn't be taken as a sign it should remain invalid. - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT(tree, MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("F"), MatchParameters(), - MatchCodeBlock(HasError, MatchNameReference("bar"), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, FunctionDefinitionWithFunctionCall) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " a.b.f(c.d, (e)).g();\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - ExpectedNode call_to_f = MatchCallExpression( - MatchDesignator(MatchDesignator(MatchNameReference("a"), "b"), "f"), - MatchDesignator(MatchNameReference("c"), "d"), MatchCallExpressionComma(), - MatchParenExpression(MatchNameReference("e"), MatchParenExpressionEnd()), - MatchCallExpressionEnd()); - ExpectedNode statement = MatchExpressionStatement(MatchCallExpression( - MatchDesignator(call_to_f, "g"), MatchCallExpressionEnd())); - - EXPECT_THAT(tree, MatchParseTreeNodes( - {MatchFunctionWithBody(statement), MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, InvalidDesignators) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " a.;\n" - " a.fn;\n" - " a.42;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - - EXPECT_THAT(tree, MatchParseTreeNodes( - {MatchFunctionWithBody( - MatchExpressionStatement( - MatchDesignatorExpression( - MatchNameReference("a"), ".", HasError), - HasError, ";"), - MatchExpressionStatement( - MatchDesignatorExpression( - MatchNameReference("a"), ".", - MatchDesignatedName("fn", HasError)), - ";"), - MatchExpressionStatement( - MatchDesignatorExpression( - MatchNameReference("a"), ".", HasError), - HasError, ";")), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, Operators) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " n = a * b + c * d = d * d << e & f - not g;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchInfixOperator( - MatchNameReference("n"), "=", - MatchInfixOperator( - MatchInfixOperator( - MatchInfixOperator(MatchNameReference("a"), "*", - MatchNameReference("b")), - "+", - MatchInfixOperator(MatchNameReference("c"), "*", - MatchNameReference("d"))), - "=", - MatchInfixOperator( - HasError, - MatchInfixOperator( - HasError, - MatchInfixOperator( - HasError, - MatchInfixOperator(MatchNameReference("d"), "*", - MatchNameReference("d")), - "<<", MatchNameReference("e")), - "&", MatchNameReference("f")), - "-", - MatchPrefixOperator("not", MatchNameReference("g"))))))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorsPrefixUnary) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " ++++n;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchPrefixOperator( - "++", MatchPrefixOperator("++", MatchNameReference("n"))))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorsPostfixUnary) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " n++++;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchPostfixOperator( - MatchPostfixOperator(MatchNameReference("n"), "++"), "++"))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorsAssociative) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " a and b and c;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchInfixOperator( - MatchInfixOperator(MatchNameReference("a"), "and", - MatchNameReference("b")), - "and", MatchNameReference("c")))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorsMissingPrecedence1) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " a and b or c;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchInfixOperator( - HasError, - MatchInfixOperator(MatchNameReference("a"), "and", - MatchNameReference("b")), - "or", MatchNameReference("c")))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorsMissingPrecedence2) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " a or b and c;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchInfixOperator( - HasError, - MatchInfixOperator(MatchNameReference("a"), "or", - MatchNameReference("b")), - "and", MatchNameReference("c")))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorsMissingPrecedenceForNot) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " not a and not b and not c;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchExpressionStatement(MatchInfixOperator( - MatchInfixOperator( - MatchPrefixOperator("not", MatchNameReference("a")), "and", - MatchPrefixOperator("not", MatchNameReference("b"))), - "and", MatchPrefixOperator("not", MatchNameReference("c"))))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, OperatorFixity) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F(p: i32*, n: i32) {\n" - " var q: i32* = p;\n" - " var t: Type = i32*;\n" - " t = t**;\n" - " n = n * n;\n" - " n = n * *p;\n" - " n = n*n;\n" - " G(i32*, n * n);\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("F"), - MatchParameters( - MatchPatternBinding( - MatchDeclaredName("p"), - MatchPostfixOperator(MatchLiteral("i32"), "*")), - MatchParameterListComma(), - MatchPatternBinding(MatchDeclaredName("n"), - MatchLiteral("i32"))), - MatchCodeBlock( - MatchVariableDeclaration( - MatchPatternBinding( - MatchDeclaredName("q"), - MatchPostfixOperator(MatchLiteral("i32"), "*")), - MatchVariableInitializer(MatchNameReference("p")), - MatchDeclarationEnd()), - MatchVariableDeclaration( - MatchPatternBinding(MatchDeclaredName("t"), - MatchNameReference("Type")), - MatchVariableInitializer( - MatchPostfixOperator(MatchLiteral("i32"), "*")), - MatchDeclarationEnd()), - MatchExpressionStatement(MatchInfixOperator( - MatchNameReference("t"), "=", - MatchPostfixOperator( - MatchPostfixOperator(MatchNameReference("t"), "*"), - "*"))), - MatchExpressionStatement(MatchInfixOperator( - MatchNameReference("n"), "=", - MatchInfixOperator(MatchNameReference("n"), "*", - MatchNameReference("n")))), - MatchExpressionStatement(MatchInfixOperator( - MatchNameReference("n"), "=", - MatchInfixOperator( - MatchNameReference("n"), "*", - MatchPrefixOperator("*", MatchNameReference("p"))))), - MatchExpressionStatement(MatchInfixOperator( - MatchNameReference("n"), "=", - MatchInfixOperator(MatchNameReference("n"), "*", - MatchNameReference("n")))), - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), - MatchPostfixOperator(MatchLiteral("i32"), "*"), - MatchCallExpressionComma(), - MatchInfixOperator(MatchNameReference("n"), "*", - MatchNameReference("n")), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - TEST_F(ParseTreeTest, OperatorWhitespaceErrors) { // Test dispositions: Recovered means we issued an error but recovered a // proper parse tree; Failed means we didn't fully recover from the error. @@ -687,432 +97,6 @@ TEST_F(ParseTreeTest, OperatorWhitespaceErrors) { } } -TEST_F(ParseTreeTest, VariableDeclarations) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "var v: i32 = 0;\n" - "var w: i32;\n" - "fn F() {\n" - " var s: String = \"hello\";\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT(tree, - MatchParseTreeNodes( - {MatchVariableDeclaration( - MatchPatternBinding(MatchDeclaredName("v"), ":", - MatchLiteral("i32")), - MatchVariableInitializer(MatchLiteral("0")), - MatchDeclarationEnd()), - MatchVariableDeclaration( - MatchPatternBinding(MatchDeclaredName("w"), ":", - MatchLiteral("i32")), - MatchDeclarationEnd()), - MatchFunctionWithBody(MatchVariableDeclaration( - MatchPatternBinding(MatchDeclaredName("s"), ":", - MatchNameReference("String")), - MatchVariableInitializer(MatchLiteral("\"hello\"")), - MatchDeclarationEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, IfNoElse) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " if (a) {\n" - " if (b) {\n" - " if (c) {\n" - " d;\n" - " }\n" - " }\n" - " }\n" - "}"); - ErrorTrackingDiagnosticConsumer error_tracker(consumer); - ParseTree tree = ParseTree::Parse(tokens, error_tracker); - EXPECT_FALSE(tree.has_errors()); - EXPECT_FALSE(error_tracker.seen_error()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchIfStatement( - MatchCondition(MatchNameReference("a"), MatchConditionEnd()), - MatchCodeBlock( - MatchIfStatement( - MatchCondition(MatchNameReference("b"), - MatchConditionEnd()), - MatchCodeBlock( - MatchIfStatement( - MatchCondition(MatchNameReference("c"), - MatchConditionEnd()), - MatchCodeBlock(MatchExpressionStatement( - MatchNameReference("d")), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd()))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, IfNoElseUnbraced) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " if (a)\n" - " if (b)\n" - " if (c)\n" - " d;\n" - "}"); - ErrorTrackingDiagnosticConsumer error_tracker(consumer); - ParseTree tree = ParseTree::Parse(tokens, error_tracker); - // The missing braces are invalid, but we should be able to recover. - EXPECT_FALSE(tree.has_errors()); - EXPECT_TRUE(error_tracker.seen_error()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchIfStatement( - MatchCondition(MatchNameReference("a"), MatchConditionEnd()), - MatchIfStatement( - MatchCondition(MatchNameReference("b"), MatchConditionEnd()), - MatchIfStatement( - MatchCondition(MatchNameReference("c"), - MatchConditionEnd()), - MatchExpressionStatement(MatchNameReference("d")))))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, IfElse) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " if (a) {\n" - " if (b) {\n" - " c;\n" - " } else {\n" - " d;\n" - " }\n" - " } else {\n" - " e;\n" - " }\n" - " if (x) { G(1); }\n" - " else if (x) { G(2); }\n" - " else { G(3); }\n" - "}"); - ErrorTrackingDiagnosticConsumer error_tracker(consumer); - ParseTree tree = ParseTree::Parse(tokens, error_tracker); - EXPECT_FALSE(tree.has_errors()); - EXPECT_FALSE(error_tracker.seen_error()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody( - MatchIfStatement( - MatchCondition(MatchNameReference("a"), MatchConditionEnd()), - MatchCodeBlock( - MatchIfStatement( - MatchCondition(MatchNameReference("b"), - MatchConditionEnd()), - MatchCodeBlock(MatchExpressionStatement( - MatchNameReference("c")), - MatchCodeBlockEnd()), - MatchIfStatementElse(), - MatchCodeBlock(MatchExpressionStatement( - MatchNameReference("d")), - MatchCodeBlockEnd())), - MatchCodeBlockEnd()), - MatchIfStatementElse(), - MatchCodeBlock( - MatchExpressionStatement(MatchNameReference("e")), - MatchCodeBlockEnd())), - MatchIfStatement( - MatchCondition(MatchNameReference("x"), MatchConditionEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), MatchLiteral("1"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd()), - MatchIfStatementElse(), - MatchIfStatement( - MatchCondition(MatchNameReference("x"), - MatchConditionEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), MatchLiteral("2"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd()), - MatchIfStatementElse(), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), MatchLiteral("3"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, IfElseUnbraced) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " if (a)\n" - " if (b)\n" - " c;\n" - " else\n" - " d;\n" - " else\n" - " e;\n" - " if (x) { G(1); }\n" - " else if (x) { G(2); }\n" - " else { G(3); }\n" - "}"); - ErrorTrackingDiagnosticConsumer error_tracker(consumer); - ParseTree tree = ParseTree::Parse(tokens, error_tracker); - // The missing braces are invalid, but we should be able to recover. - EXPECT_FALSE(tree.has_errors()); - EXPECT_TRUE(error_tracker.seen_error()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody( - MatchIfStatement( - MatchCondition(MatchNameReference("a"), MatchConditionEnd()), - MatchIfStatement( - MatchCondition(MatchNameReference("b"), - MatchConditionEnd()), - MatchExpressionStatement(MatchNameReference("c")), - MatchIfStatementElse(), - MatchExpressionStatement(MatchNameReference("d"))), - MatchIfStatementElse(), - MatchExpressionStatement(MatchNameReference("e"))), - MatchIfStatement( - MatchCondition(MatchNameReference("x"), MatchConditionEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), MatchLiteral("1"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd()), - MatchIfStatementElse(), - MatchIfStatement( - MatchCondition(MatchNameReference("x"), - MatchConditionEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), MatchLiteral("2"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd()), - MatchIfStatementElse(), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("G"), MatchLiteral("3"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, IfError) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " if a {}\n" - " if () {}\n" - " if (b c) {}\n" - " if (d)\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody( - MatchIfStatement(HasError, MatchNameReference("a"), - MatchCodeBlock(MatchCodeBlockEnd())), - MatchIfStatement(MatchCondition(HasError, MatchConditionEnd()), - MatchCodeBlock(MatchCodeBlockEnd())), - MatchIfStatement( - MatchCondition(HasError, MatchNameReference("b"), - MatchConditionEnd()), - MatchCodeBlock(MatchCodeBlockEnd())), - MatchIfStatement(HasError, - MatchCondition(MatchNameReference("d"), - MatchConditionEnd()))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, WhileBreakContinue) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " while (a) {\n" - " if (b) {\n" - " break;\n" - " }\n" - " if (c) {\n" - " continue;\n" - " }\n" - "}"); - ErrorTrackingDiagnosticConsumer error_tracker(consumer); - ParseTree tree = ParseTree::Parse(tokens, error_tracker); - EXPECT_FALSE(tree.has_errors()); - EXPECT_FALSE(error_tracker.seen_error()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchWhileStatement( - MatchCondition(MatchNameReference("a"), MatchConditionEnd()), - MatchCodeBlock( - MatchIfStatement( - MatchCondition(MatchNameReference("b"), - MatchConditionEnd()), - MatchCodeBlock(MatchBreakStatement(MatchStatementEnd()), - MatchCodeBlockEnd())), - MatchIfStatement(MatchCondition(MatchNameReference("c"), - MatchConditionEnd()), - MatchCodeBlock(MatchContinueStatement( - MatchStatementEnd()), - MatchCodeBlockEnd())), - MatchCodeBlockEnd()))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, WhileUnbraced) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " while (a) \n" - " break;\n" - "}"); - ErrorTrackingDiagnosticConsumer error_tracker(consumer); - ParseTree tree = ParseTree::Parse(tokens, error_tracker); - EXPECT_FALSE(tree.has_errors()); - EXPECT_TRUE(error_tracker.seen_error()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchWhileStatement( - MatchCondition(MatchNameReference("a"), MatchConditionEnd()), - MatchBreakStatement(MatchStatementEnd()))), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, Return) { - TokenizedBuffer tokens = GetTokenizedBuffer( - "fn F() {\n" - " if (c) {\n" - " return;\n" - " }\n" - "}\n" - "fn G(x: Foo) -> Foo {\n" - " return x;\n" - "}"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionWithBody(MatchIfStatement( - MatchCondition(MatchNameReference("c"), MatchConditionEnd()), - MatchCodeBlock(MatchReturnStatement(MatchStatementEnd()), - MatchCodeBlockEnd()))), - MatchFunctionDeclaration( - MatchDeclaredName(), - MatchParameters(MatchPatternBinding(MatchDeclaredName("x"), ":", - MatchNameReference("Foo"))), - MatchReturnType(MatchNameReference("Foo")), - MatchCodeBlock(MatchReturnStatement(MatchNameReference("x"), - MatchStatementEnd()), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, Tuples) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - var x: (i32, i32) = (1, 2); - var y: ((), (), ()); - )"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - auto empty_tuple = MatchTupleLiteral(MatchTupleLiteralEnd()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchVariableDeclaration( - MatchPatternBinding(MatchDeclaredName("x"), ":", - MatchTupleLiteral(MatchLiteral("i32"), - MatchTupleLiteralComma(), - MatchLiteral("i32"), - MatchTupleLiteralEnd())), - MatchVariableInitializer(MatchTupleLiteral( - MatchLiteral("1"), MatchTupleLiteralComma(), - MatchLiteral("2"), MatchTupleLiteralEnd())), - MatchDeclarationEnd()), - MatchVariableDeclaration( - MatchPatternBinding( - MatchDeclaredName("y"), ":", - MatchTupleLiteral(empty_tuple, MatchTupleLiteralComma(), - empty_tuple, MatchTupleLiteralComma(), - empty_tuple, MatchTupleLiteralEnd())), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, Structs) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - var x: {.a: i32, .b: i32} = {.a = 1, .b = 2}; - var y: {} = {}; - var z: {.n: i32,} = {.n = 4,}; - )"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchVariableDeclaration( - MatchPatternBinding( - MatchDeclaredName("x"), ":", - MatchStructTypeLiteral( - MatchStructFieldType(MatchStructFieldDesignator( - ".", MatchDesignatedName("a")), - ":", MatchLiteral("i32")), - MatchStructComma(), - MatchStructFieldType(MatchStructFieldDesignator( - ".", MatchDesignatedName("b")), - ":", MatchLiteral("i32")), - MatchStructEnd())), - MatchVariableInitializer(MatchStructLiteral( - MatchStructFieldValue(MatchStructFieldDesignator( - ".", MatchDesignatedName("a")), - "=", MatchLiteral("1")), - MatchStructComma(), - MatchStructFieldValue(MatchStructFieldDesignator( - ".", MatchDesignatedName("b")), - "=", MatchLiteral("2")), - MatchStructEnd())), - MatchDeclarationEnd()), - MatchVariableDeclaration( - MatchPatternBinding(MatchDeclaredName("y"), ":", - MatchStructLiteral(MatchStructEnd())), - MatchVariableInitializer(MatchStructLiteral(MatchStructEnd())), - MatchDeclarationEnd()), - MatchVariableDeclaration( - MatchPatternBinding( - MatchDeclaredName("z"), ":", - MatchStructTypeLiteral( - MatchStructFieldType(MatchStructFieldDesignator( - ".", MatchDesignatedName("n")), - ":", MatchLiteral("i32")), - MatchStructComma(), MatchStructEnd())), - MatchVariableInitializer(MatchStructLiteral( - MatchStructFieldValue(MatchStructFieldDesignator( - ".", MatchDesignatedName("n")), - "=", MatchLiteral("4")), - MatchStructComma(), MatchStructEnd())), - MatchDeclarationEnd()), - MatchFileEnd()})); -} - TEST_F(ParseTreeTest, StructErrors) { struct Testcase { llvm::StringLiteral input; @@ -1162,47 +146,6 @@ TEST_F(ParseTreeTest, StructErrors) { } } -auto GetAndDropLine(llvm::StringRef& s) -> std::string { - auto newline_offset = s.find_first_of('\n'); - llvm::StringRef line = s.slice(0, newline_offset); - - if (newline_offset != llvm::StringRef::npos) { - s = s.substr(newline_offset + 1); - } else { - s = ""; - } - - return line.str(); -} - -TEST_F(ParseTreeTest, Printing) { - TokenizedBuffer tokens = GetTokenizedBuffer("fn F();"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_FALSE(tree.has_errors()); - std::string print_storage; - llvm::raw_string_ostream print_stream(print_storage); - tree.Print(print_stream); - llvm::StringRef print = print_stream.str(); - EXPECT_THAT(GetAndDropLine(print), StrEq("[")); - EXPECT_THAT(GetAndDropLine(print), - StrEq("{node_index: 4, kind: 'FunctionDeclaration', text: 'fn', " - "subtree_size: 5, children: [")); - EXPECT_THAT(GetAndDropLine(print), - StrEq(" {node_index: 0, kind: 'DeclaredName', text: 'F'},")); - EXPECT_THAT(GetAndDropLine(print), - StrEq(" {node_index: 2, kind: 'ParameterList', text: '(', " - "subtree_size: 2, children: [")); - EXPECT_THAT(GetAndDropLine(print), - StrEq(" {node_index: 1, kind: 'ParameterListEnd', " - "text: ')'}]},")); - EXPECT_THAT(GetAndDropLine(print), - StrEq(" {node_index: 3, kind: 'DeclarationEnd', text: ';'}]},")); - EXPECT_THAT(GetAndDropLine(print), - StrEq("{node_index: 5, kind: 'FileEnd', text: ''},")); - EXPECT_THAT(GetAndDropLine(print), StrEq("]")); - EXPECT_TRUE(print.empty()) << print; -} - TEST_F(ParseTreeTest, PrintingAsYAML) { TokenizedBuffer tokens = GetTokenizedBuffer("fn F();"); ParseTree tree = ParseTree::Parse(tokens, consumer); @@ -1242,22 +185,6 @@ TEST_F(ParseTreeTest, PrintingAsYAML) { {"text", ""}}})); } -TEST_F(ParseTreeTest, ParenMatchRegression) { - // A regression test that the search for the closing `)` doesn't end early on - // the closing `}` when it skips over the nested scope. - TokenizedBuffer tokens = GetTokenizedBuffer("var = (foo {})"); - ParseTree tree = ParseTree::Parse(tokens, consumer); - EXPECT_TRUE(tree.has_errors()); - EXPECT_THAT( - tree, MatchParseTreeNodes( - {MatchVariableDeclaration( - HasError, MatchVariableInitializer( - "=", MatchParenExpression( - HasError, MatchNameReference("foo"), - MatchParenExpressionEnd()))), - MatchFileEnd()})); -} - TEST_F(ParseTreeTest, RecursionLimit) { std::string code = "fn Foo() { return "; code.append(10000, '('); @@ -1293,37 +220,6 @@ TEST_F(ParseTreeTest, ParsePostfixExpressionRegression) { } } -TEST_F(ParseTreeTest, Package) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - package Geometry api; - package Geometry impl; - package Geometry library "Shapes" api; - package Geometry library "Shapes" impl; - )"); - - ParseTree tree = ParseTree::Parse(tokens, consumer); - - EXPECT_THAT(tree, - MatchParseTreeNodes( - {MatchPackageDirective(MatchDeclaredName("Geometry"), - MatchPackageApi(), MatchPackageEnd()), - - MatchPackageDirective(MatchDeclaredName("Geometry"), - MatchPackageImpl(), MatchPackageEnd()), - - MatchPackageDirective( - MatchDeclaredName("Geometry"), - MatchPackageLibrary(MatchLiteral("\"Shapes\"")), - MatchPackageApi(), MatchPackageEnd()), - - MatchPackageDirective( - MatchDeclaredName("Geometry"), - MatchPackageLibrary(MatchLiteral("\"Shapes\"")), - MatchPackageImpl(), MatchPackageEnd()), - - MatchFileEnd()})); -} - TEST_F(ParseTreeTest, PackageErrors) { struct TestCase { llvm::StringLiteral input; @@ -1356,189 +252,5 @@ TEST_F(ParseTreeTest, PackageErrors) { } } -TEST_F(ParseTreeTest, ForSimple) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - fn foo() { - for (var x : i32 in y) { - Print(x); - } - } - )"); - - ParseTree tree = ParseTree::Parse(tokens, consumer); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), MatchParameters(), - MatchCodeBlock( - MatchForStatement( - MatchForHeader( - MatchVariableDeclaration(MatchPatternBinding( - MatchDeclaredName("x"), MatchLiteral("i32"))), - MatchForIn(), MatchNameReference("y"), - MatchForHeaderEnd()), - MatchCodeBlock( - MatchExpressionStatement( - MatchCallExpression(MatchNameReference("Print"), - MatchNameReference("x"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, ForNested) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - fn foo() { - for (var y : i32 in x) { - for (var z : i32 in y) { - Print(z); - } - } - } - )"); - - ParseTree tree = ParseTree::Parse(tokens, consumer); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), MatchParameters(), - MatchCodeBlock( - MatchForStatement( - MatchForHeader( - MatchVariableDeclaration(MatchPatternBinding( - MatchDeclaredName("y"), MatchLiteral("i32"))), - MatchForIn(), MatchNameReference("x"), - MatchForHeaderEnd()), - MatchCodeBlock( - MatchForStatement( - MatchForHeader( - MatchVariableDeclaration(MatchPatternBinding( - MatchDeclaredName("z"), - MatchLiteral("i32"))), - MatchForIn(), MatchNameReference("y"), - MatchForHeaderEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("Print"), - MatchNameReference("z"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, ForIterVarError) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - fn foo() { - for (x : i32 in y) { - Print(x); - } - } - )"); - - Testing::MockDiagnosticConsumer consumer; - EXPECT_CALL( - consumer, - HandleDiagnostic(IsDiagnosticMessage("Expected `var` declaration."))); - ParseTree tree = ParseTree::Parse(tokens, consumer); - - EXPECT_THAT(tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), MatchParameters(), - MatchCodeBlock( - MatchForStatement( - MatchForHeader(HasError, MatchForIn(), - MatchNameReference("y"), - MatchForHeaderEnd()), - MatchCodeBlock( - MatchExpressionStatement(MatchCallExpression( - MatchNameReference("Print"), - MatchNameReference("x"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, ForColonInsteafOfIn) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - fn foo() { - for (var x : i32 : y) { - Print(x); - } - } - )"); - - Testing::MockDiagnosticConsumer consumer; - EXPECT_CALL( - consumer, - HandleDiagnostic(IsDiagnosticMessage("`:` should be replaced by `in`."))); - ParseTree tree = ParseTree::Parse(tokens, consumer); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), MatchParameters(), - MatchCodeBlock( - MatchForStatement( - MatchForHeader( - HasError, - MatchVariableDeclaration(MatchPatternBinding( - MatchDeclaredName("x"), MatchLiteral("i32"))), - MatchNameReference("y"), MatchForHeaderEnd()), - MatchCodeBlock( - MatchExpressionStatement( - MatchCallExpression(MatchNameReference("Print"), - MatchNameReference("x"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - -TEST_F(ParseTreeTest, ForMissingIn) { - TokenizedBuffer tokens = GetTokenizedBuffer(R"( - fn foo() { - for (var x : i32 y) { - Print(x); - } - } - )"); - - Testing::MockDiagnosticConsumer consumer; - EXPECT_CALL(consumer, HandleDiagnostic(IsDiagnosticMessage( - "Expected `in` after loop `var` declaration."))); - ParseTree tree = ParseTree::Parse(tokens, consumer); - - EXPECT_THAT( - tree, - MatchParseTreeNodes( - {MatchFunctionDeclaration( - MatchDeclaredName("foo"), MatchParameters(), - MatchCodeBlock( - MatchForStatement( - MatchForHeader( - HasError, - MatchVariableDeclaration(MatchPatternBinding( - MatchDeclaredName("x"), MatchLiteral("i32"))), - MatchForHeaderEnd()), - MatchCodeBlock( - MatchExpressionStatement( - MatchCallExpression(MatchNameReference("Print"), - MatchNameReference("x"), - MatchCallExpressionEnd())), - MatchCodeBlockEnd())), - MatchCodeBlockEnd())), - MatchFileEnd()})); -} - } // namespace } // namespace Carbon::Testing diff --git a/toolchain/parser/testdata/BUILD b/toolchain/parser/testdata/BUILD new file mode 100644 index 000000000000..bf123a919e30 --- /dev/null +++ b/toolchain/parser/testdata/BUILD @@ -0,0 +1,16 @@ +# 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/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"], +) diff --git a/toolchain/parser/testdata/basics/empty.carbon b/toolchain/parser/testdata/basics/empty.carbon new file mode 100644 index 000000000000..72a42338695f --- /dev/null +++ b/toolchain/parser/testdata/basics/empty.carbon @@ -0,0 +1,9 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parser/testdata/basics/empty_declaration.carbon b/toolchain/parser/testdata/basics/empty_declaration.carbon new file mode 100644 index 000000000000..26cfd23252d9 --- /dev/null +++ b/toolchain/parser/testdata/basics/empty_declaration.carbon @@ -0,0 +1,12 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'EmptyDeclaration', text: ';'}, +// CHECK:STDOUT: {node_index: 1, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +; diff --git a/toolchain/parser/testdata/basics/function_call.carbon b/toolchain/parser/testdata/basics/function_call.carbon new file mode 100644 index 000000000000..20429b3e761b --- /dev/null +++ b/toolchain/parser/testdata/basics/function_call.carbon @@ -0,0 +1,39 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 24, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 25, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 23, kind: 'CodeBlock', text: '{', subtree_size: 21, children: [ +// CHECK:STDOUT: {node_index: 21, kind: 'ExpressionStatement', text: ';', subtree_size: 19, children: [ +// CHECK:STDOUT: {node_index: 20, kind: 'CallExpression', text: '(', subtree_size: 18, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'DesignatorExpression', text: '.', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'CallExpression', text: '(', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'DesignatorExpression', text: '.', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'DesignatorExpression', text: '.', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'DesignatedName', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'DesignatedName', text: 'f'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'DesignatorExpression', text: '.', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'NameReference', text: 'c'}, +// CHECK:STDOUT: {node_index: 9, kind: 'DesignatedName', text: 'd'}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'CallExpressionComma', text: ','}, +// CHECK:STDOUT: {node_index: 14, kind: 'ParenExpression', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'e'}, +// CHECK:STDOUT: {node_index: 13, kind: 'ParenExpressionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'CallExpressionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'DesignatedName', text: 'g'}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +fn F() { + a.b.f(c.d, (e)).g(); +} diff --git a/toolchain/parser/testdata/basics/invalid_designators.carbon b/toolchain/parser/testdata/basics/invalid_designators.carbon new file mode 100644 index 000000000000..1af22cc8ad22 --- /dev/null +++ b/toolchain/parser/testdata/basics/invalid_designators.carbon @@ -0,0 +1,35 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 15, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 14, kind: 'CodeBlock', text: '{', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'ExpressionStatement', text: ';', has_error: yes, subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'DesignatorExpression', text: '.', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}]}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'ExpressionStatement', text: ';', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'DesignatorExpression', text: '.', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 7, kind: 'DesignatedName', text: 'fn', has_error: yes}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'ExpressionStatement', text: ';', has_error: yes, subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'DesignatorExpression', text: '.', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'NameReference', text: 'a'}]}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +fn F() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. + a.; + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. + a.fn; + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/invalid_designators.carbon:[[@LINE+1]]:5: Expected identifier after `.`. + a.42; +} diff --git a/toolchain/parser/testdata/basics/no_intro_with_semi.carbon b/toolchain/parser/testdata/basics/no_intro_with_semi.carbon new file mode 100644 index 000000000000..61e614ddcc59 --- /dev/null +++ b/toolchain/parser/testdata/basics/no_intro_with_semi.carbon @@ -0,0 +1,13 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'EmptyDeclaration', text: ';', has_error: yes}, +// CHECK:STDOUT: {node_index: 1, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/no_intro_with_semi.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. +foo; diff --git a/toolchain/parser/testdata/basics/no_intro_without_semi.carbon b/toolchain/parser/testdata/basics/no_intro_without_semi.carbon new file mode 100644 index 000000000000..ed170f49ffa0 --- /dev/null +++ b/toolchain/parser/testdata/basics/no_intro_without_semi.carbon @@ -0,0 +1,12 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/no_intro_without_semi.carbon:[[@LINE+1]]:1: Unrecognized declaration introducer. +foo bar baz diff --git a/toolchain/parser/testdata/basics/package.carbon b/toolchain/parser/testdata/basics/package.carbon new file mode 100644 index 000000000000..875d694f4c99 --- /dev/null +++ b/toolchain/parser/testdata/basics/package.carbon @@ -0,0 +1,35 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 3, kind: 'PackageDirective', text: 'package', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'Geometry'}, +// CHECK:STDOUT: {node_index: 1, kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {node_index: 2, kind: 'PackageEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'PackageDirective', text: 'package', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'DeclaredName', text: 'Geometry'}, +// CHECK:STDOUT: {node_index: 5, kind: 'PackageImpl', text: 'impl'}, +// CHECK:STDOUT: {node_index: 6, kind: 'PackageEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'PackageDirective', text: 'package', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'DeclaredName', text: 'Geometry'}, +// CHECK:STDOUT: {node_index: 10, kind: 'PackageLibrary', text: 'library', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'Literal', text: '"Shapes"'}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {node_index: 12, kind: 'PackageEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'PackageDirective', text: 'package', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'DeclaredName', text: 'Geometry'}, +// CHECK:STDOUT: {node_index: 16, kind: 'PackageLibrary', text: 'library', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'Literal', text: '"Shapes"'}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'PackageImpl', text: 'impl'}, +// CHECK:STDOUT: {node_index: 18, kind: 'PackageEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +package Geometry api; +package Geometry impl; +package Geometry library "Shapes" api; +package Geometry library "Shapes" impl; diff --git a/toolchain/parser/testdata/basics/paren_match_regression.carbon b/toolchain/parser/testdata/basics/paren_match_regression.carbon new file mode 100644 index 000000000000..3c134e48e139 --- /dev/null +++ b/toolchain/parser/testdata/basics/paren_match_regression.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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 4, kind: 'VariableDeclaration', text: 'var', has_error: yes, subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'VariableInitializer', text: '=', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'ParenExpression', text: '(', has_error: yes, subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'NameReference', text: 'foo'}, +// CHECK:STDOUT: {node_index: 1, kind: 'ParenExpressionEnd', text: ')'}]}]}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/paren_match_regression.carbon:[[@LINE+3]]:5: Expected pattern in `var` declaration. +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/paren_match_regression.carbon:[[@LINE+2]]:12: Expected `,` or `)`. +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/basics/paren_match_regression.carbon:[[@LINE+1]]:15: Expected `;` after expression. +var = (foo {}) diff --git a/toolchain/parser/testdata/basics/return.carbon b/toolchain/parser/testdata/basics/return.carbon new file mode 100644 index 000000000000..fd879eee7576 --- /dev/null +++ b/toolchain/parser/testdata/basics/return.carbon @@ -0,0 +1,47 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 13, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'CodeBlock', text: '{', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'IfStatement', text: 'if', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'c'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'ReturnStatement', text: 'return', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'StatementEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 27, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'DeclaredName', text: 'G'}, +// CHECK:STDOUT: {node_index: 19, kind: 'ParameterList', text: '(', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'DeclaredName', text: 'x'}, +// CHECK:STDOUT: {node_index: 16, kind: 'NameReference', text: 'Foo'}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'ReturnType', text: '->', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 20, kind: 'NameReference', text: 'Foo'}]}, +// CHECK:STDOUT: {node_index: 26, kind: 'CodeBlock', text: '{', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 24, kind: 'ReturnStatement', text: 'return', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 23, kind: 'StatementEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 28, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +fn F() { + if (c) { + return; + } +} +fn G(x: Foo) -> Foo { + return x; +} diff --git a/toolchain/parser/testdata/basics/structs.carbon b/toolchain/parser/testdata/basics/structs.carbon new file mode 100644 index 000000000000..b36cc7cd6fcd --- /dev/null +++ b/toolchain/parser/testdata/basics/structs.carbon @@ -0,0 +1,69 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 26, kind: 'VariableDeclaration', text: 'var', subtree_size: 27, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'PatternBinding', text: ':', subtree_size: 13, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'x'}, +// CHECK:STDOUT: {node_index: 11, kind: 'StructTypeLiteral', text: '{', subtree_size: 11, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'StructFieldType', text: ':', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'StructFieldDesignator', text: '.', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DesignatedName', text: 'a'}]}, +// CHECK:STDOUT: {node_index: 3, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'StructComma', text: ','}, +// CHECK:STDOUT: {node_index: 9, kind: 'StructFieldType', text: ':', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'StructFieldDesignator', text: '.', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'DesignatedName', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'StructEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'VariableInitializer', text: '=', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 23, kind: 'StructLiteral', text: '{', subtree_size: 11, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'StructFieldValue', text: '=', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'StructFieldDesignator', text: '.', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'DesignatedName', text: 'a'}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'Literal', text: '1'}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'StructComma', text: ','}, +// CHECK:STDOUT: {node_index: 21, kind: 'StructFieldValue', text: '=', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 19, kind: 'StructFieldDesignator', text: '.', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'DesignatedName', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'Literal', text: '2'}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'StructEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 35, kind: 'VariableDeclaration', text: 'var', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 30, kind: 'PatternBinding', text: ':', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 27, kind: 'DeclaredName', text: 'y'}, +// CHECK:STDOUT: {node_index: 29, kind: 'StructLiteral', text: '{', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 28, kind: 'StructEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 33, kind: 'VariableInitializer', text: '=', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 32, kind: 'StructLiteral', text: '{', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 31, kind: 'StructEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 34, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 54, kind: 'VariableDeclaration', text: 'var', subtree_size: 19, children: [ +// CHECK:STDOUT: {node_index: 44, kind: 'PatternBinding', text: ':', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 36, kind: 'DeclaredName', text: 'z'}, +// CHECK:STDOUT: {node_index: 43, kind: 'StructTypeLiteral', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 40, kind: 'StructFieldType', text: ':', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 38, kind: 'StructFieldDesignator', text: '.', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 37, kind: 'DesignatedName', text: 'n'}]}, +// CHECK:STDOUT: {node_index: 39, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 41, kind: 'StructComma', text: ','}, +// CHECK:STDOUT: {node_index: 42, kind: 'StructEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 52, kind: 'VariableInitializer', text: '=', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 51, kind: 'StructLiteral', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 48, kind: 'StructFieldValue', text: '=', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 46, kind: 'StructFieldDesignator', text: '.', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 45, kind: 'DesignatedName', text: 'n'}]}, +// CHECK:STDOUT: {node_index: 47, kind: 'Literal', text: '4'}]}, +// CHECK:STDOUT: {node_index: 49, kind: 'StructComma', text: ','}, +// CHECK:STDOUT: {node_index: 50, kind: 'StructEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 53, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 55, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +var x: {.a: i32, .b: i32} = {.a = 1, .b = 2}; +var y: {} = {}; +var z: {.n: i32,} = {.n = 4,}; diff --git a/toolchain/parser/testdata/basics/tuples.carbon b/toolchain/parser/testdata/basics/tuples.carbon new file mode 100644 index 000000000000..0087619bd5bc --- /dev/null +++ b/toolchain/parser/testdata/basics/tuples.carbon @@ -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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 14, kind: 'VariableDeclaration', text: 'var', subtree_size: 15, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'PatternBinding', text: ':', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'x'}, +// CHECK:STDOUT: {node_index: 5, kind: 'TupleLiteral', text: '(', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {node_index: 2, kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {node_index: 3, kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {node_index: 4, kind: 'TupleLiteralEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'VariableInitializer', text: '=', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'TupleLiteral', text: '(', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'Literal', text: '1'}, +// CHECK:STDOUT: {node_index: 8, kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {node_index: 9, kind: 'Literal', text: '2'}, +// CHECK:STDOUT: {node_index: 10, kind: 'TupleLiteralEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 28, kind: 'VariableDeclaration', text: 'var', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 26, kind: 'PatternBinding', text: ':', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'DeclaredName', text: 'y'}, +// CHECK:STDOUT: {node_index: 25, kind: 'TupleLiteral', text: '(', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'TupleLiteral', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'TupleLiteralEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {node_index: 20, kind: 'TupleLiteral', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 19, kind: 'TupleLiteralEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {node_index: 23, kind: 'TupleLiteral', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'TupleLiteralEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'TupleLiteralEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 27, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 29, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +var x: (i32, i32) = (1, 2); +var y: ((), (), ()); diff --git a/toolchain/parser/testdata/basics/var.carbon b/toolchain/parser/testdata/basics/var.carbon new file mode 100644 index 000000000000..3bb9b9438381 --- /dev/null +++ b/toolchain/parser/testdata/basics/var.carbon @@ -0,0 +1,41 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 6, kind: 'VariableDeclaration', text: 'var', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'v'}, +// CHECK:STDOUT: {node_index: 1, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'VariableInitializer', text: '=', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'Literal', text: '0'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'VariableDeclaration', text: 'var', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'DeclaredName', text: 'w'}, +// CHECK:STDOUT: {node_index: 8, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 13, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 14, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 23, kind: 'CodeBlock', text: '{', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 21, kind: 'VariableDeclaration', text: 'var', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'DeclaredName', text: 's'}, +// CHECK:STDOUT: {node_index: 16, kind: 'NameReference', text: 'String'}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'VariableInitializer', text: '=', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'Literal', text: '"hello"'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// NOTE: Move to its own directory when more tests are added. +var v: i32 = 0; +var w: i32; +fn F() { + var s: String = "hello"; +} diff --git a/toolchain/parser/testdata/for/colon_instead_of_in.carbon b/toolchain/parser/testdata/for/colon_instead_of_in.carbon new file mode 100644 index 000000000000..4cd53bf7a46d --- /dev/null +++ b/toolchain/parser/testdata/for/colon_instead_of_in.carbon @@ -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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 20, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 21, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'CodeBlock', text: '{', subtree_size: 17, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'ForStatement', text: 'for', subtree_size: 15, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'ForHeader', text: '(', has_error: yes, subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'VariableDeclaration', text: 'var', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'DeclaredName', text: 'x'}, +// CHECK:STDOUT: {node_index: 4, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'NameReference', text: 'y'}, +// CHECK:STDOUT: {node_index: 8, kind: 'ForHeaderEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'NameReference', text: 'Print'}, +// CHECK:STDOUT: {node_index: 11, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 12, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/for/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/missing_in.carbon b/toolchain/parser/testdata/for/missing_in.carbon new file mode 100644 index 000000000000..f2dec99d4bcc --- /dev/null +++ b/toolchain/parser/testdata/for/missing_in.carbon @@ -0,0 +1,36 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 19, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 20, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'CodeBlock', text: '{', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'ForStatement', text: 'for', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'ForHeader', text: '(', has_error: yes, subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'VariableDeclaration', text: 'var', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'DeclaredName', text: 'x'}, +// CHECK:STDOUT: {node_index: 4, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'ForHeaderEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'NameReference', text: 'Print'}, +// CHECK:STDOUT: {node_index: 10, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 11, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 14, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/for/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/missing_var.carbon b/toolchain/parser/testdata/for/missing_var.carbon new file mode 100644 index 000000000000..33aedf14d877 --- /dev/null +++ b/toolchain/parser/testdata/for/missing_var.carbon @@ -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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 17, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 18, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'CodeBlock', text: '{', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'ForStatement', text: 'for', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'ForHeader', text: '(', has_error: yes, subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'ForIn', text: 'in'}, +// CHECK:STDOUT: {node_index: 4, kind: 'NameReference', text: 'y'}, +// CHECK:STDOUT: {node_index: 5, kind: 'ForHeaderEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'NameReference', text: 'Print'}, +// CHECK:STDOUT: {node_index: 8, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 9, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/for/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 new file mode 100644 index 000000000000..df95c7da3111 --- /dev/null +++ b/toolchain/parser/testdata/for/nested.carbon @@ -0,0 +1,50 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 32, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 33, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 31, kind: 'CodeBlock', text: '{', subtree_size: 29, children: [ +// CHECK:STDOUT: {node_index: 29, kind: 'ForStatement', text: 'for', subtree_size: 27, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'ForHeader', text: '(', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'VariableDeclaration', text: 'var', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'DeclaredName', text: 'y'}, +// CHECK:STDOUT: {node_index: 4, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'ForIn', text: 'in'}, +// CHECK:STDOUT: {node_index: 8, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 9, kind: 'ForHeaderEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 28, kind: 'CodeBlock', text: '{', subtree_size: 18, children: [ +// CHECK:STDOUT: {node_index: 26, kind: 'ForStatement', text: 'for', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'ForHeader', text: '(', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'VariableDeclaration', text: 'var', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'DeclaredName', text: 'z'}, +// CHECK:STDOUT: {node_index: 12, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'ForIn', text: 'in'}, +// CHECK:STDOUT: {node_index: 16, kind: 'NameReference', text: 'y'}, +// CHECK:STDOUT: {node_index: 17, kind: 'ForHeaderEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 23, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 19, kind: 'NameReference', text: 'Print'}, +// CHECK:STDOUT: {node_index: 20, kind: 'NameReference', text: 'z'}, +// CHECK:STDOUT: {node_index: 21, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 27, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 30, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 33, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() { + for (var y: i32 in x) { + for (var z: i32 in y) { + Print(z); + } + } +} diff --git a/toolchain/parser/testdata/for/simple.carbon b/toolchain/parser/testdata/for/simple.carbon new file mode 100644 index 000000000000..fa26d67e733b --- /dev/null +++ b/toolchain/parser/testdata/for/simple.carbon @@ -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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 21, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 22, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'CodeBlock', text: '{', subtree_size: 18, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'ForStatement', text: 'for', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'ForHeader', text: '(', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'VariableDeclaration', text: 'var', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'DeclaredName', text: 'x'}, +// CHECK:STDOUT: {node_index: 4, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'ForIn', text: 'in'}, +// CHECK:STDOUT: {node_index: 8, kind: 'NameReference', text: 'y'}, +// CHECK:STDOUT: {node_index: 9, kind: 'ForHeaderEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'NameReference', text: 'Print'}, +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 13, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() { + for (var x: i32 in y) { + Print(x); + } +} diff --git a/toolchain/parser/testdata/function/declaration/basic.carbon b/toolchain/parser/testdata/function/declaration/basic.carbon new file mode 100644 index 000000000000..1743d1c1ab61 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/basic.carbon @@ -0,0 +1,16 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 4, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 3, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F(); diff --git a/toolchain/parser/testdata/function/declaration/identifier_instead_of_sig.carbon b/toolchain/parser/testdata/function/declaration/identifier_instead_of_sig.carbon new file mode 100644 index 000000000000..bb48c88cab85 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/identifier_instead_of_sig.carbon @@ -0,0 +1,15 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 2, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 1, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 3, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/identifier_instead_of_sig.carbon:[[@LINE+1]]:8: Expected `(` after function name. +fn foo bar; diff --git a/toolchain/parser/testdata/function/declaration/missing_name.carbon b/toolchain/parser/testdata/function/declaration/missing_name.carbon new file mode 100644 index 000000000000..5d366ba89037 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/missing_name.carbon @@ -0,0 +1,14 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 1, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 2, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/missing_name.carbon:[[@LINE+1]]:4: Expected function name after `fn` keyword. +fn (); diff --git a/toolchain/parser/testdata/function/declaration/no_sig_or_semi.carbon b/toolchain/parser/testdata/function/declaration/no_sig_or_semi.carbon new file mode 100644 index 000000000000..effdf253e0b5 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/no_sig_or_semi.carbon @@ -0,0 +1,14 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 1, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}]}, +// CHECK:STDOUT: {node_index: 2, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/no_sig_or_semi.carbon:[[@LINE+1]]:7: Expected `(` after function name. +fn foo diff --git a/toolchain/parser/testdata/function/declaration/only_fn_and_semi.carbon b/toolchain/parser/testdata/function/declaration/only_fn_and_semi.carbon new file mode 100644 index 000000000000..68825a8a6039 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/only_fn_and_semi.carbon @@ -0,0 +1,14 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 1, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 2, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/only_fn_and_semi.carbon:[[@LINE+1]]:3: Expected function name after `fn` keyword. +fn; diff --git a/toolchain/parser/testdata/function/declaration/repeated_fn_and_semi.carbon b/toolchain/parser/testdata/function/declaration/repeated_fn_and_semi.carbon new file mode 100644 index 000000000000..8be2c76d3627 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/repeated_fn_and_semi.carbon @@ -0,0 +1,14 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 1, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 2, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/repeated_fn_and_semi.carbon:[[@LINE+1]]:4: Expected function name after `fn` keyword. +fn fn; diff --git a/toolchain/parser/testdata/function/declaration/skip_indented_newline_until_outdent.carbon b/toolchain/parser/testdata/function/declaration/skip_indented_newline_until_outdent.carbon new file mode 100644 index 000000000000..1aaca74656d5 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/skip_indented_newline_until_outdent.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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'FunctionDeclaration', text: 'fn', has_error: yes}, +// CHECK:STDOUT: {node_index: 5, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 3, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/skip_indented_newline_until_outdent.carbon:[[@LINE+1]]:6: Expected function name after `fn` keyword. + fn (x, + y, + z) +fn F(); diff --git a/toolchain/parser/testdata/function/declaration/skip_indented_newline_with_semi.carbon b/toolchain/parser/testdata/function/declaration/skip_indented_newline_with_semi.carbon new file mode 100644 index 000000000000..9e7ea70c6f08 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/skip_indented_newline_with_semi.carbon @@ -0,0 +1,22 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 1, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/skip_indented_newline_with_semi.carbon:[[@LINE+1]]:4: Expected function name after `fn` keyword. +fn (x, + y, + z); +fn F(); diff --git a/toolchain/parser/testdata/function/declaration/skip_indented_newline_without_semi.carbon b/toolchain/parser/testdata/function/declaration/skip_indented_newline_without_semi.carbon new file mode 100644 index 000000000000..877a4d62e5fa --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/skip_indented_newline_without_semi.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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'FunctionDeclaration', text: 'fn', has_error: yes}, +// CHECK:STDOUT: {node_index: 5, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 3, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/skip_indented_newline_without_semi.carbon:[[@LINE+1]]:4: Expected function name after `fn` keyword. +fn (x, + y, + z) +fn F(); diff --git a/toolchain/parser/testdata/function/declaration/skip_to_newline_without_semi.carbon b/toolchain/parser/testdata/function/declaration/skip_to_newline_without_semi.carbon new file mode 100644 index 000000000000..256bf702edf3 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/skip_to_newline_without_semi.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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 0, kind: 'FunctionDeclaration', text: 'fn', has_error: yes}, +// CHECK:STDOUT: {node_index: 5, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 3, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/skip_to_newline_without_semi.carbon:[[@LINE+1]]:4: Expected function name after `fn` keyword. +fn () +fn F(); diff --git a/toolchain/parser/testdata/function/declaration/skip_without_semi_to_curly.carbon b/toolchain/parser/testdata/function/declaration/skip_without_semi_to_curly.carbon new file mode 100644 index 000000000000..ad283e38436d --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/skip_without_semi_to_curly.carbon @@ -0,0 +1,18 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 4, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 3, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/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/with_identifier_as_param.carbon b/toolchain/parser/testdata/function/declaration/with_identifier_as_param.carbon new file mode 100644 index 000000000000..e8e3cef7f30a --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/with_identifier_as_param.carbon @@ -0,0 +1,17 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 4, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 3, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/with_identifier_as_param.carbon:[[@LINE+1]]:8: Expected parameter declaration. +fn foo(bar); diff --git a/toolchain/parser/testdata/function/declaration/with_params.carbon b/toolchain/parser/testdata/function/declaration/with_params.carbon new file mode 100644 index 000000000000..07071d517b11 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/with_params.carbon @@ -0,0 +1,23 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 11, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 9, kind: 'ParameterList', text: '(', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DeclaredName', text: 'bar'}, +// CHECK:STDOUT: {node_index: 2, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {node_index: 7, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'DeclaredName', text: 'baz'}, +// CHECK:STDOUT: {node_index: 6, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo(bar: i32, baz: i32); diff --git a/toolchain/parser/testdata/function/declaration/with_return_type.carbon b/toolchain/parser/testdata/function/declaration/with_return_type.carbon new file mode 100644 index 000000000000..a830fa38a407 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/with_return_type.carbon @@ -0,0 +1,18 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 6, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'ReturnType', text: '->', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'Literal', text: 'u32'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() -> u32; diff --git a/toolchain/parser/testdata/function/declaration/without_name_and_many_tokens_in_params.carbon b/toolchain/parser/testdata/function/declaration/without_name_and_many_tokens_in_params.carbon new file mode 100644 index 000000000000..f6c0e8d7ce51 --- /dev/null +++ b/toolchain/parser/testdata/function/declaration/without_name_and_many_tokens_in_params.carbon @@ -0,0 +1,14 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 1, kind: 'FunctionDeclaration', text: 'fn', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 2, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/function/declaration/without_name_and_many_tokens_in_params.carbon:[[@LINE+1]]:4: Expected function name after `fn` keyword. +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/definition/basic.carbon b/toolchain/parser/testdata/function/definition/basic.carbon new file mode 100644 index 000000000000..47d6f6898e8c --- /dev/null +++ b/toolchain/parser/testdata/function/definition/basic.carbon @@ -0,0 +1,18 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 5, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'CodeBlock', text: '{', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { +} diff --git a/toolchain/parser/testdata/function/definition/identifier_in_statements.carbon b/toolchain/parser/testdata/function/definition/identifier_in_statements.carbon new file mode 100644 index 000000000000..cb45aa48c59d --- /dev/null +++ b/toolchain/parser/testdata/function/definition/identifier_in_statements.carbon @@ -0,0 +1,23 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 6, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'CodeBlock', text: '{', has_error: yes, subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'bar'}, +// CHECK:STDOUT: {node_index: 4, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +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/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 new file mode 100644 index 000000000000..57d6ff34a3ce --- /dev/null +++ b/toolchain/parser/testdata/function/definition/with_params.carbon @@ -0,0 +1,35 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 21, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 22, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 9, kind: 'ParameterList', text: '(', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DeclaredName', text: 'bar'}, +// CHECK:STDOUT: {node_index: 2, kind: 'Literal', text: 'i64'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {node_index: 7, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'DeclaredName', text: 'baz'}, +// CHECK:STDOUT: {node_index: 6, kind: 'Literal', text: 'i64'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'CodeBlock', text: '{', subtree_size: 11, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'ExpressionStatement', text: ';', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'CallExpression', text: '(', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'NameReference', text: 'foo'}, +// CHECK:STDOUT: {node_index: 11, kind: 'NameReference', text: 'baz'}, +// CHECK:STDOUT: {node_index: 12, kind: 'CallExpressionComma', text: ','}, +// CHECK:STDOUT: {node_index: 15, kind: 'InfixOperator', text: '+', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'NameReference', text: 'bar'}, +// CHECK:STDOUT: {node_index: 14, kind: 'NameReference', text: 'baz'}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo(bar: i64, baz: i64) { + foo(baz, bar + baz); +} diff --git a/toolchain/parser/testdata/function/definition/with_return_type.carbon b/toolchain/parser/testdata/function/definition/with_return_type.carbon new file mode 100644 index 000000000000..627fe8023ab8 --- /dev/null +++ b/toolchain/parser/testdata/function/definition/with_return_type.carbon @@ -0,0 +1,24 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 10, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 11, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'foo'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 4, kind: 'ReturnType', text: '->', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'Literal', text: 'f64'}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlock', text: '{', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'ReturnStatement', text: 'return', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Literal', text: '42'}, +// CHECK:STDOUT: {node_index: 6, kind: 'StatementEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn foo() -> f64 { + return 42; +} diff --git a/toolchain/parser/testdata/if/basic.carbon b/toolchain/parser/testdata/if/basic.carbon new file mode 100644 index 000000000000..c11f7b8cfd01 --- /dev/null +++ b/toolchain/parser/testdata/if/basic.carbon @@ -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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 25, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 26, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'CodeBlock', text: '{', subtree_size: 22, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'IfStatement', text: 'if', subtree_size: 20, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'CodeBlock', text: '{', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 19, kind: 'IfStatement', text: 'if', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'b'}, +// CHECK:STDOUT: {node_index: 7, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'CodeBlock', text: '{', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'IfStatement', text: 'if', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'NameReference', text: 'c'}, +// CHECK:STDOUT: {node_index: 10, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'd'}]}, +// CHECK:STDOUT: {node_index: 14, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 23, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 26, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + if (a) { + if (b) { + if (c) { + d; + } + } + } +} diff --git a/toolchain/parser/testdata/if/else.carbon b/toolchain/parser/testdata/if/else.carbon new file mode 100644 index 000000000000..92cb870f71ea --- /dev/null +++ b/toolchain/parser/testdata/if/else.carbon @@ -0,0 +1,85 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 60, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 61, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 59, kind: 'CodeBlock', text: '{', subtree_size: 57, children: [ +// CHECK:STDOUT: {node_index: 26, kind: 'IfStatement', text: 'if', subtree_size: 24, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'CodeBlock', text: '{', subtree_size: 15, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'IfStatement', text: 'if', subtree_size: 13, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'b'}, +// CHECK:STDOUT: {node_index: 7, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'NameReference', text: 'c'}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'CodeBlockEnd', text: '}'}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 17, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'NameReference', text: 'd'}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'CodeBlockEnd', text: '}'}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 25, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 23, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'NameReference', text: 'e'}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 57, kind: 'IfStatement', text: 'if', subtree_size: 31, children: [ +// CHECK:STDOUT: {node_index: 29, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 27, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 28, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 36, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 34, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 33, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 30, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 31, kind: 'Literal', text: '1'}, +// CHECK:STDOUT: {node_index: 32, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 35, kind: 'CodeBlockEnd', text: '}'}]}, +// CHECK:STDOUT: {node_index: 37, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 56, kind: 'IfStatement', text: 'if', subtree_size: 19, children: [ +// CHECK:STDOUT: {node_index: 40, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 38, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 39, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 47, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 45, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 44, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 41, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 42, kind: 'Literal', text: '2'}, +// CHECK:STDOUT: {node_index: 43, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 46, kind: 'CodeBlockEnd', text: '}'}]}, +// CHECK:STDOUT: {node_index: 48, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 55, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 53, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 52, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 49, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 50, kind: 'Literal', text: '3'}, +// CHECK:STDOUT: {node_index: 51, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 54, kind: 'CodeBlockEnd', text: '}'}]}]}]}, +// CHECK:STDOUT: {node_index: 58, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 61, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + if (a) { + if (b) { + c; + } else { + d; + } + } else { + e; + } + if (x) { G(1); } + else if (x) { G(2); } + else { G(3); } +} diff --git a/toolchain/parser/testdata/if/else_unbraced.carbon b/toolchain/parser/testdata/if/else_unbraced.carbon new file mode 100644 index 000000000000..9b8d417fbff2 --- /dev/null +++ b/toolchain/parser/testdata/if/else_unbraced.carbon @@ -0,0 +1,79 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 52, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 53, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 51, kind: 'CodeBlock', text: '{', subtree_size: 49, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'IfStatement', text: 'if', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 14, kind: 'IfStatement', text: 'if', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'b'}, +// CHECK:STDOUT: {node_index: 7, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'NameReference', text: 'c'}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 13, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'd'}]}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 17, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'NameReference', text: 'e'}]}]}, +// CHECK:STDOUT: {node_index: 49, kind: 'IfStatement', text: 'if', subtree_size: 31, children: [ +// CHECK:STDOUT: {node_index: 21, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 19, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 20, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 28, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 26, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 25, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 23, kind: 'Literal', text: '1'}, +// CHECK:STDOUT: {node_index: 24, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 27, kind: 'CodeBlockEnd', text: '}'}]}, +// CHECK:STDOUT: {node_index: 29, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 48, kind: 'IfStatement', text: 'if', subtree_size: 19, children: [ +// CHECK:STDOUT: {node_index: 32, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 30, kind: 'NameReference', text: 'x'}, +// CHECK:STDOUT: {node_index: 31, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 39, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 37, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 36, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 33, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 34, kind: 'Literal', text: '2'}, +// CHECK:STDOUT: {node_index: 35, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 38, kind: 'CodeBlockEnd', text: '}'}]}, +// CHECK:STDOUT: {node_index: 40, kind: 'IfStatementElse', text: 'else'}, +// CHECK:STDOUT: {node_index: 47, kind: 'CodeBlock', text: '{', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 45, kind: 'ExpressionStatement', text: ';', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 44, kind: 'CallExpression', text: '(', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 41, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 42, kind: 'Literal', text: '3'}, +// CHECK:STDOUT: {node_index: 43, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 46, kind: 'CodeBlockEnd', text: '}'}]}]}]}, +// CHECK:STDOUT: {node_index: 50, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 53, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + if (a) + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/else_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + if (b) + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/else_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. + c; + else + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/else_unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. + d; + else + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/else_unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + e; + if (x) { G(1); } + else if (x) { G(2); } + else { G(3); } +} diff --git a/toolchain/parser/testdata/if/errors.carbon b/toolchain/parser/testdata/if/errors.carbon new file mode 100644 index 000000000000..b66a04a84555 --- /dev/null +++ b/toolchain/parser/testdata/if/errors.carbon @@ -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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 24, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 25, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 23, kind: 'CodeBlock', text: '{', subtree_size: 21, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'IfStatement', text: 'if', has_error: yes, subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 5, kind: 'CodeBlock', text: '{', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'IfStatement', text: 'if', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'Condition', text: '(', has_error: yes, subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'CodeBlock', text: '{', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'IfStatement', text: 'if', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'Condition', text: '(', has_error: yes, subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'b'}, +// CHECK:STDOUT: {node_index: 13, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'CodeBlock', text: '{', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'IfStatement', text: 'if', has_error: yes, subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 20, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'NameReference', text: 'd'}, +// CHECK:STDOUT: {node_index: 19, kind: 'ConditionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/errors.carbon:[[@LINE+1]]:6: Expected `(` after `if`. + if a {} + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/errors.carbon:[[@LINE+1]]:7: Expected expression. + if () {} + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/errors.carbon:[[@LINE+1]]:9: Unexpected tokens before `)`. + if (b c) {} + if (d) +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/errors.carbon:[[@LINE+2]]:1: Expected braced code block. +// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/errors.carbon:[[@LINE+1]]:1: Expected expression. +} diff --git a/toolchain/parser/testdata/if/unbraced.carbon b/toolchain/parser/testdata/if/unbraced.carbon new file mode 100644 index 000000000000..27ec23bdd5a6 --- /dev/null +++ b/toolchain/parser/testdata/if/unbraced.carbon @@ -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 +// +// TODO: This should have an error. +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 19, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 20, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 18, kind: 'CodeBlock', text: '{', subtree_size: 16, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'IfStatement', text: 'if', subtree_size: 14, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'IfStatement', text: 'if', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'b'}, +// CHECK:STDOUT: {node_index: 7, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 14, kind: 'IfStatement', text: 'if', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'NameReference', text: 'c'}, +// CHECK:STDOUT: {node_index: 10, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'ExpressionStatement', text: ';', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'd'}]}]}]}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + if (a) + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + if (b) + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/unbraced.carbon:[[@LINE+1]]:7: Expected braced code block. + if (c) + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/if/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 new file mode 120000 index 000000000000..c323f8a5e8da --- /dev/null +++ b/toolchain/parser/testdata/lit.cfg.py @@ -0,0 +1 @@ +../../../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 new file mode 100644 index 000000000000..588387181aff --- /dev/null +++ b/toolchain/parser/testdata/operators/associative.carbon @@ -0,0 +1,25 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 11, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'CodeBlock', text: '{', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'ExpressionStatement', text: ';', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'InfixOperator', text: 'and', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'InfixOperator', text: 'and', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'NameReference', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'c'}]}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + a and b and c; +} diff --git a/toolchain/parser/testdata/operators/fixity.carbon b/toolchain/parser/testdata/operators/fixity.carbon new file mode 100644 index 000000000000..c24d9e2696d6 --- /dev/null +++ b/toolchain/parser/testdata/operators/fixity.carbon @@ -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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 64, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 65, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 10, kind: 'ParameterList', text: '(', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'PatternBinding', text: ':', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'DeclaredName', text: 'p'}, +// CHECK:STDOUT: {node_index: 3, kind: 'PostfixOperator', text: '*', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 2, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 5, kind: 'ParameterListComma', text: ','}, +// CHECK:STDOUT: {node_index: 8, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'DeclaredName', text: 'n'}, +// CHECK:STDOUT: {node_index: 7, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 63, kind: 'CodeBlock', text: '{', subtree_size: 53, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'VariableDeclaration', text: 'var', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'PatternBinding', text: ':', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'DeclaredName', text: 'q'}, +// CHECK:STDOUT: {node_index: 13, kind: 'PostfixOperator', text: '*', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 12, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'VariableInitializer', text: '=', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'NameReference', text: 'p'}]}, +// CHECK:STDOUT: {node_index: 17, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 26, kind: 'VariableDeclaration', text: 'var', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 21, kind: 'PatternBinding', text: ':', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 19, kind: 'DeclaredName', text: 't'}, +// CHECK:STDOUT: {node_index: 20, kind: 'NameReference', text: 'Type'}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'VariableInitializer', text: '=', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 23, kind: 'PostfixOperator', text: '*', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'Literal', text: 'i32'}]}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'DeclarationEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 32, kind: 'ExpressionStatement', text: ';', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 31, kind: 'InfixOperator', text: '=', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 27, kind: 'NameReference', text: 't'}, +// CHECK:STDOUT: {node_index: 30, kind: 'PostfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 29, kind: 'PostfixOperator', text: '*', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 28, kind: 'NameReference', text: 't'}]}]}]}]}, +// CHECK:STDOUT: {node_index: 38, kind: 'ExpressionStatement', text: ';', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 37, kind: 'InfixOperator', text: '=', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 33, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 36, kind: 'InfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 34, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 35, kind: 'NameReference', text: 'n'}]}]}]}, +// CHECK:STDOUT: {node_index: 45, kind: 'ExpressionStatement', text: ';', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 44, kind: 'InfixOperator', text: '=', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 39, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 43, kind: 'InfixOperator', text: '*', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 40, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 42, kind: 'PrefixOperator', text: '*', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 41, kind: 'NameReference', text: 'p'}]}]}]}]}, +// CHECK:STDOUT: {node_index: 51, kind: 'ExpressionStatement', text: ';', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 50, kind: 'InfixOperator', text: '=', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 46, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 49, kind: 'InfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 47, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 48, kind: 'NameReference', text: 'n'}]}]}]}, +// CHECK:STDOUT: {node_index: 61, kind: 'ExpressionStatement', text: ';', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 60, kind: 'CallExpression', text: '(', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 52, kind: 'NameReference', text: 'G'}, +// CHECK:STDOUT: {node_index: 54, kind: 'PostfixOperator', text: '*', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 53, kind: 'Literal', text: 'i32'}]}, +// CHECK:STDOUT: {node_index: 55, kind: 'CallExpressionComma', text: ','}, +// CHECK:STDOUT: {node_index: 58, kind: 'InfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 56, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 57, kind: 'NameReference', text: 'n'}]}, +// CHECK:STDOUT: {node_index: 59, kind: 'CallExpressionEnd', text: ')'}]}]}, +// CHECK:STDOUT: {node_index: 62, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 65, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F(p: i32*, n: i32) { + var q: i32* = p; + var t: Type = i32*; + t = t**; + n = n * n; + n = n * *p; + n = n*n; + G(i32*, n * n); +} diff --git a/toolchain/parser/testdata/operators/missing_precedence_and_or.carbon b/toolchain/parser/testdata/operators/missing_precedence_and_or.carbon new file mode 100644 index 000000000000..2297b44bb132 --- /dev/null +++ b/toolchain/parser/testdata/operators/missing_precedence_and_or.carbon @@ -0,0 +1,26 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 11, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'CodeBlock', text: '{', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'ExpressionStatement', text: ';', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'InfixOperator', text: 'or', has_error: yes, subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'InfixOperator', text: 'and', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'NameReference', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'c'}]}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/missing_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/missing_precedence_not.carbon b/toolchain/parser/testdata/operators/missing_precedence_not.carbon new file mode 100644 index 000000000000..5ac08bc47952 --- /dev/null +++ b/toolchain/parser/testdata/operators/missing_precedence_not.carbon @@ -0,0 +1,31 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 14, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 15, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 13, kind: 'CodeBlock', text: '{', subtree_size: 11, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'ExpressionStatement', text: ';', subtree_size: 9, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'InfixOperator', text: 'and', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'InfixOperator', text: 'and', subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'PrefixOperator', text: 'not', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'PrefixOperator', text: 'not', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'NameReference', text: 'b'}]}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'PrefixOperator', text: 'not', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'NameReference', text: 'c'}]}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 15, kind: 'FileEnd', text: ''}, +// 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. + not a and not b and not c; +} diff --git a/toolchain/parser/testdata/operators/missing_precedence_or_and.carbon b/toolchain/parser/testdata/operators/missing_precedence_or_and.carbon new file mode 100644 index 000000000000..0f4c5172db9c --- /dev/null +++ b/toolchain/parser/testdata/operators/missing_precedence_or_and.carbon @@ -0,0 +1,26 @@ +// 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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 11, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'CodeBlock', text: '{', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'ExpressionStatement', text: ';', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'InfixOperator', text: 'and', has_error: yes, subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'InfixOperator', text: 'or', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'NameReference', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'c'}]}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/missing_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/postfix_unary.carbon b/toolchain/parser/testdata/operators/postfix_unary.carbon new file mode 100644 index 000000000000..11a3c9ff6f8f --- /dev/null +++ b/toolchain/parser/testdata/operators/postfix_unary.carbon @@ -0,0 +1,23 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 9, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'CodeBlock', text: '{', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'ExpressionStatement', text: ';', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'PostfixOperator', text: '++', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'PostfixOperator', text: '++', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'n'}]}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + n++++; +} diff --git a/toolchain/parser/testdata/operators/prefix_unary.carbon b/toolchain/parser/testdata/operators/prefix_unary.carbon new file mode 100644 index 000000000000..921d86bd1d08 --- /dev/null +++ b/toolchain/parser/testdata/operators/prefix_unary.carbon @@ -0,0 +1,23 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 9, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 8, kind: 'CodeBlock', text: '{', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'ExpressionStatement', text: ';', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'PrefixOperator', text: '++', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'PrefixOperator', text: '++', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'n'}]}]}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + ++++n; +} diff --git a/toolchain/parser/testdata/operators/variety.carbon b/toolchain/parser/testdata/operators/variety.carbon new file mode 100644 index 000000000000..821a057f18fa --- /dev/null +++ b/toolchain/parser/testdata/operators/variety.carbon @@ -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 +// +// RUN: %{not} %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 26, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 27, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'CodeBlock', text: '{', subtree_size: 23, children: [ +// CHECK:STDOUT: {node_index: 23, kind: 'ExpressionStatement', text: ';', subtree_size: 21, children: [ +// CHECK:STDOUT: {node_index: 22, kind: 'InfixOperator', text: '=', subtree_size: 20, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'n'}, +// CHECK:STDOUT: {node_index: 21, kind: 'InfixOperator', text: '=', subtree_size: 18, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'InfixOperator', text: '+', subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'InfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 4, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 5, kind: 'NameReference', text: 'b'}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'InfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 7, kind: 'NameReference', text: 'c'}, +// CHECK:STDOUT: {node_index: 8, kind: 'NameReference', text: 'd'}]}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'InfixOperator', text: '-', has_error: yes, subtree_size: 10, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'InfixOperator', text: '&', has_error: yes, subtree_size: 7, children: [ +// CHECK:STDOUT: {node_index: 15, kind: 'InfixOperator', text: '<<', has_error: yes, subtree_size: 5, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'InfixOperator', text: '*', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 11, kind: 'NameReference', text: 'd'}, +// CHECK:STDOUT: {node_index: 12, kind: 'NameReference', text: 'd'}]}, +// CHECK:STDOUT: {node_index: 14, kind: 'NameReference', text: 'e'}]}, +// CHECK:STDOUT: {node_index: 16, kind: 'NameReference', text: 'f'}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'PrefixOperator', text: 'not', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'NameReference', text: 'g'}]}]}]}]}]}, +// CHECK:STDOUT: {node_index: 24, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 27, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/variety.carbon:[[@LINE+4]]:29: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/variety.carbon:[[@LINE+3]]:34: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/variety.carbon:[[@LINE+2]]:38: Parentheses are required to disambiguate operator precedence. + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/operators/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/while/basic.carbon b/toolchain/parser/testdata/while/basic.carbon new file mode 100644 index 000000000000..6072ae8723d5 --- /dev/null +++ b/toolchain/parser/testdata/while/basic.carbon @@ -0,0 +1,48 @@ +// 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 +// +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 27, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 28, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 26, kind: 'CodeBlock', text: '{', subtree_size: 24, children: [ +// CHECK:STDOUT: {node_index: 24, kind: 'WhileStatement', text: 'while', subtree_size: 22, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 23, kind: 'CodeBlock', text: '{', subtree_size: 18, children: [ +// CHECK:STDOUT: {node_index: 13, kind: 'IfStatement', text: 'if', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'NameReference', text: 'b'}, +// CHECK:STDOUT: {node_index: 7, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 10, kind: 'BreakStatement', text: 'break', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 9, kind: 'StatementEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 11, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 21, kind: 'IfStatement', text: 'if', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 16, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 14, kind: 'NameReference', text: 'c'}, +// CHECK:STDOUT: {node_index: 15, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 20, kind: 'CodeBlock', text: '{', subtree_size: 4, children: [ +// CHECK:STDOUT: {node_index: 18, kind: 'ContinueStatement', text: 'continue', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 17, kind: 'StatementEnd', text: ';'}]}, +// CHECK:STDOUT: {node_index: 19, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 22, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 25, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 28, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + while (a) { + if (b) { + break; + } + if (c) { + continue; + } + } +} diff --git a/toolchain/parser/testdata/while/unbraced.carbon b/toolchain/parser/testdata/while/unbraced.carbon new file mode 100644 index 000000000000..e9b19cb9de17 --- /dev/null +++ b/toolchain/parser/testdata/while/unbraced.carbon @@ -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 +// +// TODO: This should have an error. +// RUN: %{carbon} dump parse-tree %s | %{FileCheck-strict} %s +// AUTOUPDATE: %{carbon} dump parse-tree %s +// CHECK:STDOUT: [ +// CHECK:STDOUT: {node_index: 11, kind: 'FunctionDeclaration', text: 'fn', subtree_size: 12, children: [ +// CHECK:STDOUT: {node_index: 0, kind: 'DeclaredName', text: 'F'}, +// CHECK:STDOUT: {node_index: 2, kind: 'ParameterList', text: '(', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 1, kind: 'ParameterListEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 10, kind: 'CodeBlock', text: '{', subtree_size: 8, children: [ +// CHECK:STDOUT: {node_index: 8, kind: 'WhileStatement', text: 'while', subtree_size: 6, children: [ +// CHECK:STDOUT: {node_index: 5, kind: 'Condition', text: '(', subtree_size: 3, children: [ +// CHECK:STDOUT: {node_index: 3, kind: 'NameReference', text: 'a'}, +// CHECK:STDOUT: {node_index: 4, kind: 'ConditionEnd', text: ')'}]}, +// CHECK:STDOUT: {node_index: 7, kind: 'BreakStatement', text: 'break', subtree_size: 2, children: [ +// CHECK:STDOUT: {node_index: 6, kind: 'StatementEnd', text: ';'}]}]}, +// CHECK:STDOUT: {node_index: 9, kind: 'CodeBlockEnd', text: '}'}]}]}, +// CHECK:STDOUT: {node_index: 12, kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] + +fn F() { + while (a) + // CHECK:STDERR: {{.*}}/toolchain/parser/testdata/while/unbraced.carbon:[[@LINE+1]]:5: Expected braced code block. + break; +}