From 30960d11a9f474f23fcaeb0bbff0bbcdb68f9094 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Wed, 7 Dec 2022 15:10:42 -0800 Subject: [PATCH] Start adding var decls to semantics. (#2447) This is just the declaration, without initialization. Partly breaking it out because I'm changing the placeholder builtin types. Might also need to separate out storage of the var from the name bind. --- .../semantics/semantics_builtin_kind.def | 10 ++-- toolchain/semantics/semantics_ir.cpp | 13 +++-- toolchain/semantics/semantics_node.h | 4 +- .../semantics_parse_tree_handler.cpp | 51 ++++++++++++++++++- .../semantics/semantics_parse_tree_handler.h | 11 ++-- toolchain/semantics/testdata/var/decl.carbon | 25 +++++++++ .../semantics/testdata/var/global_decl.carbon | 33 ++++++++++++ 7 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 toolchain/semantics/testdata/var/decl.carbon create mode 100644 toolchain/semantics/testdata/var/global_decl.carbon diff --git a/toolchain/semantics/semantics_builtin_kind.def b/toolchain/semantics/semantics_builtin_kind.def index b5b1402ba8c1..e45848ddd885 100644 --- a/toolchain/semantics/semantics_builtin_kind.def +++ b/toolchain/semantics/semantics_builtin_kind.def @@ -20,11 +20,13 @@ CARBON_SEMANTICS_BUILTIN_KIND(TypeType) // for future type checking. CARBON_SEMANTICS_BUILTIN_KIND(InvalidType) -// The type of an integer literal. -CARBON_SEMANTICS_BUILTIN_KIND(IntegerLiteralType) +// The type of integers and integer literals, currently always i32. Long-term +// we may not want it this way, but for now this is the approach. +CARBON_SEMANTICS_BUILTIN_KIND(IntegerType) -// The type of a real literal. -CARBON_SEMANTICS_BUILTIN_KIND(RealLiteralType) +// The type of reals and real literals, currently always f64. Long-term +// we may not want it this way, but for now this is the approach. +CARBON_SEMANTICS_BUILTIN_KIND(RealType) // Keep invalid last, so that we can use values as array indices without needing // an invalid entry. diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index 57c627d21a1b..bfb5a64d1210 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -39,16 +39,15 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR { << "InvalidType's type must be self-referential."; auto integer_literal_type = semantics.AddNode( - block_id, SemanticsNode::MakeBuiltin( - SemanticsBuiltinKind::IntegerLiteralType(), type_type)); - semantics - .cross_references_[SemanticsBuiltinKind::IntegerLiteralType().AsInt()] = + block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::IntegerType(), + type_type)); + semantics.cross_references_[SemanticsBuiltinKind::IntegerType().AsInt()] = SemanticsCrossReference(BuiltinIR, block_id, integer_literal_type); auto real_literal_type = semantics.AddNode( - block_id, SemanticsNode::MakeBuiltin( - SemanticsBuiltinKind::RealLiteralType(), type_type)); - semantics.cross_references_[SemanticsBuiltinKind::RealLiteralType().AsInt()] = + block_id, + SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::RealType(), type_type)); + semantics.cross_references_[SemanticsBuiltinKind::RealType().AsInt()] = SemanticsCrossReference(BuiltinIR, block_id, real_literal_type); CARBON_CHECK(semantics.node_blocks_.size() == 1) diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 6d6149c91037..af0a87b80d95 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -148,7 +148,7 @@ class SemanticsNode { -> SemanticsNode { return SemanticsNode(parse_node, SemanticsNodeKind::IntegerLiteral(), SemanticsNodeId::MakeBuiltinReference( - SemanticsBuiltinKind::IntegerLiteralType()), + SemanticsBuiltinKind::IntegerType()), integer.index); } auto GetAsIntegerLiteral() const -> SemanticsIntegerLiteralId { @@ -159,7 +159,7 @@ class SemanticsNode { static auto MakeRealLiteral(ParseTree::Node parse_node) -> SemanticsNode { return SemanticsNode(parse_node, SemanticsNodeKind::RealLiteral(), SemanticsNodeId::MakeBuiltinReference( - SemanticsBuiltinKind::RealLiteralType())); + SemanticsBuiltinKind::RealType())); } auto GetAsRealLiteral() const -> NoArgs { CARBON_CHECK(kind_ == SemanticsNodeKind::RealLiteral()); diff --git a/toolchain/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp index e3b10ac1627c..58c4cf0c83b6 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -98,14 +98,23 @@ auto SemanticsParseTreeHandler::Build() -> void { HandleParameterList(parse_node); break; } + case ParseNodeKind::PatternBinding(): { + HandlePatternBinding(parse_node); + break; + } case ParseNodeKind::ReturnStatement(): { HandleReturnStatement(parse_node); break; } + case ParseNodeKind::VariableDeclaration(): { + HandleVariableDeclaration(parse_node); + break; + } case ParseNodeKind::DeclaredName(): case ParseNodeKind::FunctionIntroducer(): case ParseNodeKind::ParameterListStart(): - case ParseNodeKind::ReturnStatementStart(): { + case ParseNodeKind::ReturnStatementStart(): + case ParseNodeKind::VariableIntroducer(): { // The token has no action, but we still track it for the stack. Push(parse_node); break; @@ -144,6 +153,16 @@ auto SemanticsParseTreeHandler::Push(ParseTree::Node parse_node, node_stack_.push_back({parse_node, node_id}); } +auto SemanticsParseTreeHandler::Push(ParseTree::Node parse_node, + SemanticsNodeId node_id) -> void { + CARBON_VLOG() << "Push " << node_stack_.size() << ": " + << parse_tree_->node_kind(parse_node) << " -> " << node_id + << "\n"; + CARBON_CHECK(node_stack_.size() < (1 << 20)) + << "Excessive stack size: likely infinite loop"; + node_stack_.push_back({parse_node, node_id}); +} + auto SemanticsParseTreeHandler::Pop(ParseNodeKind pop_parse_kind) -> void { auto back = node_stack_.pop_back_val(); auto parse_kind = parse_tree_->node_kind(back.parse_node); @@ -262,6 +281,13 @@ auto SemanticsParseTreeHandler::HandleLiteral(ParseTree::Node parse_node) Push(parse_node, SemanticsNode::MakeRealLiteral(parse_node)); break; } + case TokenKind::IntegerTypeLiteral(): { + auto text = tokens_->GetTokenText(token); + CARBON_CHECK(text == "i32") << "Currently only i32 is allowed"; + Push(parse_node, SemanticsNodeId::MakeBuiltinReference( + SemanticsBuiltinKind::IntegerType())); + break; + } default: CARBON_FATAL() << "Unhandled kind: " << token_kind.Name(); } @@ -277,6 +303,20 @@ auto SemanticsParseTreeHandler::HandleParameterList(ParseTree::Node parse_node) Push(parse_node); } +auto SemanticsParseTreeHandler::HandlePatternBinding(ParseTree::Node parse_node) + -> void { + // TODO: Create storage for the type, use that for the bind instead of the + // type itself. + auto type_id = PopWithResult(); + + auto name_node = node_stack_.back().parse_node; + auto name = AddIdentifier(name_node); + node_stack_.pop_back(); + + Push(parse_node, + AddNode(SemanticsNode::MakeBindName(name_node, name, type_id))); +} + auto SemanticsParseTreeHandler::HandleReturnStatement( ParseTree::Node parse_node) -> void { if (parse_tree_->node_kind(node_stack_.back().parse_node) == @@ -292,4 +332,13 @@ auto SemanticsParseTreeHandler::HandleReturnStatement( } } +auto SemanticsParseTreeHandler::HandleVariableDeclaration( + ParseTree::Node parse_node) -> void { + // TODO: Initializers would assign to the PatternBinding, but this code + // doesn't handle it right now. + PopWithResult(); + Pop(ParseNodeKind::VariableIntroducer()); + Push(parse_node); +} + } // namespace Carbon diff --git a/toolchain/semantics/semantics_parse_tree_handler.h b/toolchain/semantics/semantics_parse_tree_handler.h index 7dd883a713c5..a6166564756e 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.h +++ b/toolchain/semantics/semantics_parse_tree_handler.h @@ -46,14 +46,17 @@ class SemanticsParseTreeHandler { // Adds a node to the current block, returning the produced ID. auto AddNode(SemanticsNode node) -> SemanticsNodeId; - // Pushes a parse tree onto the stack. Used when there is no IR generated by - // the node. + // Pushes a parse tree node onto the stack. Used when there is no IR generated + // by the node. auto Push(ParseTree::Node parse_node) -> void; - // Pushes a parse tree onto the stack, storing the SemanticsNode as the + // Pushes a parse tree node onto the stack, storing the SemanticsNode as the // result. auto Push(ParseTree::Node parse_node, SemanticsNode node) -> void; + // Pushes a parse tree node onto the stack with an already-built node ID. + auto Push(ParseTree::Node parse_node, SemanticsNodeId node_id) -> void; + // Pops the top of the stack, verifying that it's the expected kind. auto Pop(ParseNodeKind pop_parse_kind) -> void; @@ -72,7 +75,9 @@ class SemanticsParseTreeHandler { auto HandleInfixOperator(ParseTree::Node parse_node) -> void; auto HandleLiteral(ParseTree::Node parse_node) -> void; auto HandleParameterList(ParseTree::Node parse_node) -> void; + auto HandlePatternBinding(ParseTree::Node parse_node) -> void; auto HandleReturnStatement(ParseTree::Node parse_node) -> void; + auto HandleVariableDeclaration(ParseTree::Node parse_node) -> void; // Tokens for getting data on literals. const TokenizedBuffer* tokens_; diff --git a/toolchain/semantics/testdata/var/decl.carbon b/toolchain/semantics/testdata/var/decl.carbon new file mode 100644 index 000000000000..4fa20f857dc4 --- /dev/null +++ b/toolchain/semantics/testdata/var/decl.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 +// +// AUTOUPDATE +// RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); +// CHECK:STDOUT: }, +// CHECK:STDOUT: identifiers = { +// CHECK:STDOUT: ident0 = "x"; +// CHECK:STDOUT: }, +// CHECK:STDOUT: integer_literals = { +// CHECK:STDOUT: }, +// CHECK:STDOUT: node_blocks = { +// CHECK:STDOUT: block0 = { +// CHECK:STDOUT: node0 = BindName(ident0, node_xref2); +// CHECK:STDOUT: }, +// CHECK:STDOUT: } + +var x: i32; diff --git a/toolchain/semantics/testdata/var/global_decl.carbon b/toolchain/semantics/testdata/var/global_decl.carbon new file mode 100644 index 000000000000..e4a29084cb5c --- /dev/null +++ b/toolchain/semantics/testdata/var/global_decl.carbon @@ -0,0 +1,33 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = xref(ir0, block0, node0); +// CHECK:STDOUT: node_xref1 = xref(ir0, block0, node1); +// CHECK:STDOUT: node_xref2 = xref(ir0, block0, node2); +// CHECK:STDOUT: node_xref3 = xref(ir0, block0, node3); +// CHECK:STDOUT: }, +// CHECK:STDOUT: identifiers = { +// CHECK:STDOUT: ident0 = "Main"; +// CHECK:STDOUT: ident1 = "x"; +// CHECK:STDOUT: }, +// CHECK:STDOUT: integer_literals = { +// CHECK:STDOUT: }, +// CHECK:STDOUT: node_blocks = { +// CHECK:STDOUT: block0 = { +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); +// CHECK:STDOUT: }, +// CHECK:STDOUT: block1 = { +// CHECK:STDOUT: node0 = BindName(ident1, node_xref2); +// CHECK:STDOUT: }, +// CHECK:STDOUT: } + +fn Main() { + var x: i32; +}