From def98d11826b4eebb00a31fcf8d3b812e686db46 Mon Sep 17 00:00:00 2001 From: Geoff Romer Date: Mon, 19 Jul 2021 10:33:06 -0700 Subject: [PATCH] Add support for `_` placeholder. (#661) Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com> --- executable_semantics/BUILD | 3 +++ executable_semantics/ast/expression.cpp | 15 +++++++++++---- executable_semantics/ast/expression.h | 7 +++++-- executable_semantics/interpreter/interpreter.cpp | 10 +++++++--- executable_semantics/interpreter/typecheck.cpp | 10 ++++++---- executable_semantics/interpreter/value.cpp | 13 ++++++++++--- executable_semantics/interpreter/value.h | 7 ++++--- executable_semantics/syntax/lexer.lpp | 2 ++ executable_semantics/syntax/parser.ypp | 8 +++++++- .../testdata/ignored_parameter.carbon | 11 +++++++++++ .../testdata/ignored_parameter.golden | 1 + .../testdata/match_placeholder.carbon | 11 +++++++++++ .../testdata/match_placeholder.golden | 1 + .../testdata/placeholder_variable.carbon | 8 ++++++++ .../testdata/placeholder_variable.golden | 1 + 15 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 executable_semantics/testdata/ignored_parameter.carbon create mode 100644 executable_semantics/testdata/ignored_parameter.golden create mode 100644 executable_semantics/testdata/match_placeholder.carbon create mode 100644 executable_semantics/testdata/match_placeholder.golden create mode 100644 executable_semantics/testdata/placeholder_variable.carbon create mode 100644 executable_semantics/testdata/placeholder_variable.golden diff --git a/executable_semantics/BUILD b/executable_semantics/BUILD index cd31241be808..45e5d9b510f9 100644 --- a/executable_semantics/BUILD +++ b/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", diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp index 43f727bdf2da..371c989f32ba 100644 --- a/executable_semantics/ast/expression.cpp +++ b/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 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() == diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h index aad8e406cdaa..9f9b7c543d7d 100644 --- a/executable_semantics/ast/expression.h +++ b/executable_semantics/ast/expression.h @@ -5,6 +5,7 @@ #ifndef EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_ #define EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_ +#include #include #include #include @@ -74,7 +75,8 @@ struct IndexExpression { struct BindingExpression { static constexpr ExpressionKind Kind = ExpressionKind::BindingExpression; - std::string name; + // nullopt represents the `_` placeholder. + std::optional 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 var, const Expression* type) -> const Expression*; static auto MakeIntLiteral(int line_num, int i) -> const Expression*; diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp index dcfca4adec57..271c8dffb70e 100644 --- a/executable_semantics/interpreter/interpreter.cpp +++ b/executable_semantics/interpreter/interpreter.cpp @@ -384,9 +384,13 @@ auto PatternMatch(const Value* p, const Value* v, Env values, -> std::optional { 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: diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp index ec7b5d1ff969..f67393b29f5d 100644 --- a/executable_semantics/interpreter/typecheck.cpp +++ b/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& 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: { diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp index 106977cbe1f2..303501a037ae 100644 --- a/executable_semantics/interpreter/value.cpp +++ b/executable_semantics/interpreter/value.cpp @@ -171,8 +171,8 @@ auto Value::MakeContinuationValue(std::vector stack) -> Value* { return v; } -auto Value::MakeBindingPlaceholderValue(std::string name, const Value* type) - -> const Value* { +auto Value::MakeBindingPlaceholderValue(std::optional 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: { diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h index d89e71c7097e..66c9a899ebfa 100644 --- a/executable_semantics/interpreter/value.h +++ b/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 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 name, + const Value* type) -> const Value*; static auto MakeIntType() -> const Value*; static auto MakeContinuationType() -> const Value*; static auto MakeAutoType() -> const Value*; diff --git a/executable_semantics/syntax/lexer.lpp b/executable_semantics/syntax/lexer.lpp index 1d881de32b58..1ac3e5cebf64 100644 --- a/executable_semantics/syntax/lexer.lpp +++ b/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); diff --git a/executable_semantics/syntax/parser.ypp b/executable_semantics/syntax/parser.ypp index 4aac4e843f2f..82ac9ddeaf43 100644 --- a/executable_semantics/syntax/parser.ypp +++ b/executable_semantics/syntax/parser.ypp @@ -104,6 +104,7 @@ void yy::parser::error( %type return_type %type paren_expression %type tuple +%type > binding_lhs %type variable_declaration %type member %type > 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); } diff --git a/executable_semantics/testdata/ignored_parameter.carbon b/executable_semantics/testdata/ignored_parameter.carbon new file mode 100644 index 000000000000..fbe00104243c --- /dev/null +++ b/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); +} diff --git a/executable_semantics/testdata/ignored_parameter.golden b/executable_semantics/testdata/ignored_parameter.golden new file mode 100644 index 000000000000..2db2755da426 --- /dev/null +++ b/executable_semantics/testdata/ignored_parameter.golden @@ -0,0 +1 @@ +result: 0 diff --git a/executable_semantics/testdata/match_placeholder.carbon b/executable_semantics/testdata/match_placeholder.carbon new file mode 100644 index 000000000000..7b9fddc045dd --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/match_placeholder.golden b/executable_semantics/testdata/match_placeholder.golden new file mode 100644 index 000000000000..2db2755da426 --- /dev/null +++ b/executable_semantics/testdata/match_placeholder.golden @@ -0,0 +1 @@ +result: 0 diff --git a/executable_semantics/testdata/placeholder_variable.carbon b/executable_semantics/testdata/placeholder_variable.carbon new file mode 100644 index 000000000000..2fb18aded34d --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/placeholder_variable.golden b/executable_semantics/testdata/placeholder_variable.golden new file mode 100644 index 000000000000..2db2755da426 --- /dev/null +++ b/executable_semantics/testdata/placeholder_variable.golden @@ -0,0 +1 @@ +result: 0