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; +}