Преглед изворни кода

Add support for `_` placeholder. (#661)

Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
Geoff Romer пре 4 година
родитељ
комит
def98d1182

+ 3 - 0
executable_semantics/BUILD

@@ -50,16 +50,19 @@ EXAMPLES = [
     "global_variable6",
     "global_variable7",
     "global_variable8",
+    "ignored_parameter",
     "if1",
     "if2",
     "if3",
     "match_any_int",
     "match_int_default",
     "match_int",
+    "match_placeholder",
     "match_type",
     "next",
     "pattern_init",
     "pattern_variable_fail",
+    "placeholder_variable",
     "record1",
     "star",
     "struct1",

+ 11 - 4
executable_semantics/ast/expression.cpp

@@ -105,7 +105,8 @@ auto Expression::MakeIdentifierExpression(int line_num, std::string var)
   return v;
 }
 
-auto Expression::MakeBindingExpression(int line_num, std::string var,
+auto Expression::MakeBindingExpression(int line_num,
+                                       std::optional<std::string> var,
                                        const Expression* type)
     -> const Expression* {
   auto* v = new Expression();
@@ -280,11 +281,17 @@ void PrintExp(const Expression* e) {
     case ExpressionKind::IdentifierExpression:
       std::cout << e->GetIdentifierExpression().name;
       break;
-    case ExpressionKind::BindingExpression:
-      PrintExp(e->GetBindingExpression().type);
+    case ExpressionKind::BindingExpression: {
+      const BindingExpression& binding = e->GetBindingExpression();
+      if (binding.name.has_value()) {
+        std::cout << *binding.name;
+      } else {
+        std::cout << "_";
+      }
       std::cout << ": ";
-      std::cout << e->GetBindingExpression().name;
+      PrintExp(e->GetBindingExpression().type);
       break;
+    }
     case ExpressionKind::CallExpression:
       PrintExp(e->GetCallExpression().function);
       if (e->GetCallExpression().argument->tag() ==

+ 5 - 2
executable_semantics/ast/expression.h

@@ -5,6 +5,7 @@
 #ifndef EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_
 #define EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_
 
+#include <optional>
 #include <string>
 #include <variant>
 #include <vector>
@@ -74,7 +75,8 @@ struct IndexExpression {
 
 struct BindingExpression {
   static constexpr ExpressionKind Kind = ExpressionKind::BindingExpression;
-  std::string name;
+  // nullopt represents the `_` placeholder.
+  std::optional<std::string> name;
   const Expression* type;
 };
 
@@ -136,7 +138,8 @@ struct TypeTypeLiteral {
 struct Expression {
   static auto MakeIdentifierExpression(int line_num, std::string var)
       -> const Expression*;
-  static auto MakeBindingExpression(int line_num, std::string var,
+  static auto MakeBindingExpression(int line_num,
+                                    std::optional<std::string> var,
                                     const Expression* type)
       -> const Expression*;
   static auto MakeIntLiteral(int line_num, int i) -> const Expression*;

+ 7 - 3
executable_semantics/interpreter/interpreter.cpp

@@ -384,9 +384,13 @@ auto PatternMatch(const Value* p, const Value* v, Env values,
     -> std::optional<Env> {
   switch (p->tag()) {
     case ValKind::BindingPlaceholderValue: {
-      Address a = state->heap.AllocateValue(CopyVal(v, line_num));
-      vars->push_back(p->GetBindingPlaceholderValue().name);
-      values.Set(p->GetBindingPlaceholderValue().name, a);
+      const BindingPlaceholderValue& placeholder =
+          p->GetBindingPlaceholderValue();
+      if (placeholder.name.has_value()) {
+        Address a = state->heap.AllocateValue(CopyVal(v, line_num));
+        vars->push_back(*placeholder.name);
+        values.Set(*placeholder.name, a);
+      }
       return values;
     }
     case ValKind::TupleValue:

+ 6 - 4
executable_semantics/interpreter/typecheck.cpp

@@ -153,10 +153,12 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values,
       } else if (expected) {
         ExpectType(e->line_num, "pattern variable", t, expected);
       }
-      auto new_e = Expression::MakeBindingExpression(
-          e->line_num, e->GetBindingExpression().name,
-          ReifyType(t, e->line_num));
-      types.Set(e->GetBindingExpression().name, t);
+      const std::optional<std::string>& name = e->GetBindingExpression().name;
+      auto new_e = Expression::MakeBindingExpression(e->line_num, name,
+                                                     ReifyType(t, e->line_num));
+      if (name.has_value()) {
+        types.Set(*name, t);
+      }
       return TCResult(new_e, t, types);
     }
     case ExpressionKind::IndexExpression: {

+ 10 - 3
executable_semantics/interpreter/value.cpp

@@ -171,8 +171,8 @@ auto Value::MakeContinuationValue(std::vector<Frame*> stack) -> Value* {
   return v;
 }
 
-auto Value::MakeBindingPlaceholderValue(std::string name, const Value* type)
-    -> const Value* {
+auto Value::MakeBindingPlaceholderValue(std::optional<std::string> name,
+                                        const Value* type) -> const Value* {
   auto* v = new Value();
   v->value = BindingPlaceholderValue({.name = std::move(name), .type = type});
   return v;
@@ -352,8 +352,15 @@ auto PrintValue(const Value* val, std::ostream& out) -> void {
       break;
     }
     case ValKind::BindingPlaceholderValue: {
+      const BindingPlaceholderValue& placeholder =
+          val->GetBindingPlaceholderValue();
+      if (placeholder.name.has_value()) {
+        out << *placeholder.name;
+      } else {
+        out << "_";
+      }
+      out << ": ";
       PrintValue(val->GetBindingPlaceholderValue().type, out);
-      out << ": " << val->GetBindingPlaceholderValue().name;
       break;
     }
     case ValKind::AlternativeValue: {

+ 4 - 3
executable_semantics/interpreter/value.h

@@ -110,7 +110,8 @@ struct TupleValue {
 
 struct BindingPlaceholderValue {
   static constexpr ValKind Kind = ValKind::BindingPlaceholderValue;
-  std::string name;
+  // nullopt represents the `_` placeholder
+  std::optional<std::string> name;
   const Value* type;
 };
 
@@ -183,8 +184,8 @@ struct Value {
   static auto MakeAlternativeConstructorValue(std::string alt_name,
                                               std::string choice_name)
       -> const Value*;
-  static auto MakeBindingPlaceholderValue(std::string name, const Value* type)
-      -> const Value*;
+  static auto MakeBindingPlaceholderValue(std::optional<std::string> name,
+                                          const Value* type) -> const Value*;
   static auto MakeIntType() -> const Value*;
   static auto MakeContinuationType() -> const Value*;
   static auto MakeAutoType() -> const Value*;

+ 2 - 0
executable_semantics/syntax/lexer.lpp

@@ -56,6 +56,7 @@ CONTINUATION_TYPE "__Continuation"
 CONTINUATION      "__continuation"
 RUN               "__run"
 AWAIT             "__await"
+UNDERSCORE        "_"
 
 identifier    [A-Za-z_][A-Za-z0-9_]*
 integer_literal   [0-9]+
@@ -116,6 +117,7 @@ operand_start [(A-Za-z0-9_"]
 {CONTINUATION}    { return yy::parser::make_CONTINUATION(context.current_token_position); }
 {RUN}      { return yy::parser::make_RUN(context.current_token_position); }
 {AWAIT}    { return yy::parser::make_AWAIT(context.current_token_position); }
+{UNDERSCORE}      { return yy::parser::make_UNDERSCORE(context.current_token_position); }
 
 "=" return yy::parser::make_EQUAL(context.current_token_position);
 "-" return yy::parser::make_MINUS(context.current_token_position);

+ 7 - 1
executable_semantics/syntax/parser.ypp

@@ -104,6 +104,7 @@ void yy::parser::error(
 %type <const Carbon::Expression*> return_type
 %type <const Carbon::Expression*> paren_expression
 %type <const Carbon::Expression*> tuple
+%type <std::optional<std::string>> binding_lhs
 %type <Carbon::Member*> variable_declaration
 %type <Carbon::Member*> member
 %type <std::list<Carbon::Member*>> member_list
@@ -146,6 +147,7 @@ void yy::parser::error(
 %token DBLARROW "=>"
 %token DEFAULT
 %token AUTO
+%token UNDERSCORE
 %token
   EQUAL  "="
   MINUS  "-"
@@ -199,6 +201,10 @@ pattern:
   expression
     { $$ = $1; }
 ;
+binding_lhs:
+  identifier { $$ = $1; }
+| UNDERSCORE { $$ = std::nullopt; }
+;
 expression:
   identifier
     { $$ = Carbon::Expression::MakeIdentifierExpression(yylineno, $1); }
@@ -206,7 +212,7 @@ expression:
     { $$ = Carbon::Expression::MakeFieldAccessExpression(yylineno, $1, $2); }
 | expression "[" expression "]"
     { $$ = Carbon::Expression::MakeIndexExpression(yylineno, $1, $3); }
-| identifier ":" expression
+| binding_lhs ":" expression
     {
       $$ = Carbon::Expression::MakeBindingExpression(yylineno, $1, $3);
     }

+ 11 - 0
executable_semantics/testdata/ignored_parameter.carbon

@@ -0,0 +1,11 @@
+// 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
+
+fn ReturnSecond(_: Int, x: Int) -> Int {
+  return x;
+}
+
+fn main() -> Int {
+  return ReturnSecond(1, 0);
+}

+ 1 - 0
executable_semantics/testdata/ignored_parameter.golden

@@ -0,0 +1 @@
+result: 0

+ 11 - 0
executable_semantics/testdata/match_placeholder.carbon

@@ -0,0 +1,11 @@
+// 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
+
+fn main() -> Int {
+  var t: auto = (1, 2, 3, 4);
+  match (t) {
+    case (_: Int, _: auto, x: Int, y: auto) =>
+      return y - x - 1;
+  }
+}

+ 1 - 0
executable_semantics/testdata/match_placeholder.golden

@@ -0,0 +1 @@
+result: 0

+ 8 - 0
executable_semantics/testdata/placeholder_variable.carbon

@@ -0,0 +1,8 @@
+// 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
+
+fn main() -> Int {
+  var _: auto = 1;
+  return 0;
+}

+ 1 - 0
executable_semantics/testdata/placeholder_variable.golden

@@ -0,0 +1 @@
+result: 0