diff --git a/zetasql/parser/ast_node_kind.h b/zetasql/parser/ast_node_kind.h index 1a5b57552..e457647b1 100755 --- a/zetasql/parser/ast_node_kind.h +++ b/zetasql/parser/ast_node_kind.h @@ -328,6 +328,7 @@ enum ASTNodeKind { AST_WINDOW_ATTRIBUTE_INST_NOT_IN_WINDOW, AST_WINDOW_ATTRIBUTE_LIST, AST_LIKE_TABLE_CLAUSE, + AST_EXIT_STATEMENT, kLastASTNodeKind = AST_LIKE_TABLE_CLAUSE, }; diff --git a/zetasql/parser/bison_parser.y b/zetasql/parser/bison_parser.y index ad0f0aa6b..4fb435c9b 100644 --- a/zetasql/parser/bison_parser.y +++ b/zetasql/parser/bison_parser.y @@ -924,6 +924,8 @@ using zetasql::ASTDropStatement; %token KW_STORED "STORED" %token KW_STORING "STORING" %token KW_STOP "STOP" +%token KW_QUIT "QUIT" +%token KW_EXIT "EXIT" %token KW_SYSTEM "SYSTEM" %token KW_SYSTEM_TIME "SYSTEM_TIME" %token KW_TABLE "TABLE" @@ -1135,6 +1137,7 @@ using zetasql::ASTDropStatement; %type model_clause %type module_statement %type use_statement +%type exit_statement %type nested_dml_statement %type new_constructor %type new_constructor_arg @@ -1614,6 +1617,7 @@ sql_statement_body: | load_statement | into_statement | stop_statement + | exit_statement ; query_statement: @@ -7603,6 +7607,8 @@ keyword_as_identifier: | "STORED" | "STORING" | "STOP" + | "QUIT" + | "EXIT" | "SYSTEM" | "SYSTEM_TIME" | "TABLE" @@ -8426,6 +8432,11 @@ stop_statement: } ; +exit_statement: + "EXIT" { $$ = MAKE_NODE(ASTExitStatement, @$); } + | "QUIT" { $$ = MAKE_NODE(ASTExitStatement, @$); } + ; + opt_drop_mode: "RESTRICT" { $$ = zetasql::ASTDropStatement::DropMode::RESTRICT; } | "CASCADE" { $$ = zetasql::ASTDropStatement::DropMode::CASCADE; } @@ -9108,6 +9119,10 @@ next_statement_kind_without_hint: { $$ = zetasql::ASTUseStatement::kConcreteNodeKind; } | "STOP" { $$ = zetasql::ASTStopStatement::kConcreteNodeKind; } + | "EXIT" + { $$ = zetasql::ASTExitStatement::kConcreteNodeKind; } + | "QUIT" + { $$ = zetasql::ASTExitStatement::kConcreteNodeKind; } ; %% diff --git a/zetasql/parser/flex_tokenizer.l b/zetasql/parser/flex_tokenizer.l index a2fd61c8b..d3f386b6c 100644 --- a/zetasql/parser/flex_tokenizer.l +++ b/zetasql/parser/flex_tokenizer.l @@ -624,6 +624,8 @@ status { return BisonParserImpl::token::KW_STATUS; } stored { return BisonParserImpl::token::KW_STORED; } storing { return BisonParserImpl::token::KW_STORING; } stop { return BisonParserImpl::token::KW_STOP; } +quit { return BisonParserImpl::token::KW_QUIT; } +exit { return BisonParserImpl::token::KW_EXIT; } struct { return BisonParserImpl::token::KW_STRUCT; } system { return BisonParserImpl::token::KW_SYSTEM; } system_time { return BisonParserImpl::token::KW_SYSTEM_TIME; } diff --git a/zetasql/parser/keywords.cc b/zetasql/parser/keywords.cc index 1d02e006d..2e42647b3 100644 --- a/zetasql/parser/keywords.cc +++ b/zetasql/parser/keywords.cc @@ -276,6 +276,8 @@ constexpr KeywordInfoPOD kAllKeywords[] = { {"source", KW_SOURCE}, {"storing", KW_STORING}, {"stop", KW_STOP}, + {"exit", KW_EXIT}, + {"quit", KW_QUIT}, {"sql", KW_SQL}, {"stable", KW_STABLE}, {"start", KW_START}, diff --git a/zetasql/parser/parse_tree.cc b/zetasql/parser/parse_tree.cc index 384a75159..1886cfcd2 100644 --- a/zetasql/parser/parse_tree.cc +++ b/zetasql/parser/parse_tree.cc @@ -356,6 +356,7 @@ static absl::flat_hash_map CreateNodeNamesMap() { map[AST_SELECT_INTO_STATEMENT] = "SelectIntoStatement"; map[AST_ESCAPED_EXPRESSION] = "EscapedExpression"; map[AST_STOP_STATEMENT] = "StopStatement"; + map[AST_EXIT_STATEMENT] = "ExitStatement"; map[AST_CONFIG_CLAUSE] = "ConfigClause"; map[AST_WITH_WEIGHT] = "WithWeight"; map[AST_WITH_PARTITION_COLUMNS_CLAUSE] = "WithPartitionColumnsClause"; diff --git a/zetasql/parser/parse_tree_manual.h b/zetasql/parser/parse_tree_manual.h index 3d19135f8..0d48902a1 100644 --- a/zetasql/parser/parse_tree_manual.h +++ b/zetasql/parser/parse_tree_manual.h @@ -697,6 +697,20 @@ class ASTStopStatement final : public ASTStatement { const ASTTargetName* target_name_ = nullptr; }; +class ASTExitStatement final : public ASTStatement { + public: + static constexpr ASTNodeKind kConcreteNodeKind = AST_EXIT_STATEMENT; + + ASTExitStatement() : ASTStatement(kConcreteNodeKind) {} + void Accept(ParseTreeVisitor* visitor, void* data) const override; + zetasql_base::StatusOr Accept( + NonRecursiveParseTreeVisitor* visitor) const override; + + private: + void InitFields() final {} +}; + + // Represents a RENAME statement. class ASTRenameStatement final : public ASTStatement { public: diff --git a/zetasql/parser/testdata/exit.test b/zetasql/parser/testdata/exit.test new file mode 100644 index 000000000..66c2a2996 --- /dev/null +++ b/zetasql/parser/testdata/exit.test @@ -0,0 +1,27 @@ +EXIT; +-- +ExitStatement [0-4] +-- +EXIT +== + +QUIT; +-- +ExitStatement [0-4] +-- +EXIT +== + +QUIT ; +-- +ExitStatement [0-4] +-- +EXIT +== + +EXIT aaa; +-- +ERROR: Syntax error: Expected end of input but got identifier "aaa" [at 1:6] +EXIT aaa; + ^ +== diff --git a/zetasql/parser/unparser.cc b/zetasql/parser/unparser.cc index c17543fc5..b61f4c9cf 100644 --- a/zetasql/parser/unparser.cc +++ b/zetasql/parser/unparser.cc @@ -904,6 +904,10 @@ void Unparser::visitASTStopStatement(const ASTStopStatement* node, void* data) { node->target_name()->Accept(this, data); } +void Unparser::visitASTExitStatement(const ASTExitStatement* node, void* data) { + print("EXIT"); +} + void Unparser::visitASTBeginStatement( const ASTBeginStatement* node, void* data) { print("BEGIN TRANSACTION"); diff --git a/zetasql/parser/unparser.h b/zetasql/parser/unparser.h index 5aadfc202..3c80ffadd 100644 --- a/zetasql/parser/unparser.h +++ b/zetasql/parser/unparser.h @@ -195,6 +195,7 @@ class Unparser : public ParseTreeVisitor { void* data) override; void visitASTDeployStatement(const ASTDeployStatement* node, void* data) override; void visitASTStopStatement(const ASTStopStatement* node, void* data) override; + void visitASTExitStatement(const ASTExitStatement* node, void* data) override; void visitASTBeginStatement(const ASTBeginStatement* node, void* data) override; void visitASTTransactionIsolationLevel(