<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

grammar Cql;

options {
    language = Cpp;
}

@parser::namespace{cql3_parser}

@lexer::includes {
#include "cql3/error_listener.hh"
}

@parser::includes {
#include "cql3/statements/create_keyspace_statement.hh"
#include "cql3/statements/create_table_statement.hh"
#include "cql3/statements/property_definitions.hh"
#include "cql3/statements/select_statement.hh"
#include "cql3/statements/update_statement.hh"
#include "cql3/statements/delete_statement.hh"
#include "cql3/statements/use_statement.hh"
#include "cql3/statements/ks_prop_defs.hh"
#include "cql3/selection/raw_selector.hh"
#include "cql3/constants.hh"
#include "cql3/operation_impl.hh"
#include "cql3/error_listener.hh"
#include "cql3/single_column_relation.hh"
#include "cql3/cql3_type.hh"
#include "cql3/cf_name.hh"
#include "cql3/maps.hh"
#include "cql3/sets.hh"
#include "cql3/lists.hh"
#include "cql3/functions/function_name.hh"
#include "cql3/functions/function_call.hh"
#include "core/sstring.hh"
#include "CqlLexer.hpp"

#include <unordered_map>
}

@parser::traits {
using namespace cql3::statements;
using namespace cql3::selection;
using cql3::cql3_type;
using conditions_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::column_condition::raw>>>;
using operations_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>;
}

@context {
    using listener_type = cql3::error_listener<RecognizerType>;
    listener_type* listener;

    std::vector<::shared_ptr<cql3::column_identifier>> _bind_variables;

#if 0
    public static final Set<String> reservedTypeNames = new HashSet<String>()
    {{
        add("byte");
        add("smallint");
        add("complex");
        add("enum");
        add("date");
        add("interval");
        add("macaddr");
        add("bitstring");
    }};
#endif

    shared_ptr<cql3::abstract_marker::raw> new_bind_variables(shared_ptr<cql3::column_identifier> name)
    {
        auto marker = make_shared<cql3::abstract_marker::raw>(_bind_variables.size());
        _bind_variables.push_back(name);
        return marker;
    }

#if 0
    public AbstractMarker.INRaw newINBindVariables(ColumnIdentifier name)
    {
        AbstractMarker.INRaw marker = new AbstractMarker.INRaw(bindVariables.size());
        bindVariables.add(name);
        return marker;
    }

    public Tuples.Raw newTupleBindVariables(ColumnIdentifier name)
    {
        Tuples.Raw marker = new Tuples.Raw(bindVariables.size());
        bindVariables.add(name);
        return marker;
    }

    public Tuples.INRaw newTupleINBindVariables(ColumnIdentifier name)
    {
        Tuples.INRaw marker = new Tuples.INRaw(bindVariables.size());
        bindVariables.add(name);
        return marker;
    }
#endif

    void set_error_listener(listener_type& listener) {
        this->listener = &listener;
    }

#if 0
    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
    {
        for (int i = 0, m = listeners.size(); i < m; i++)
            listeners.get(i).syntaxError(this, tokenNames, e);
    }
#endif

    void add_recognition_error(const sstring& msg) {
        listener->syntax_error(*this, msg);
    }

    std::unordered_map<sstring, sstring> convert_property_map(shared_ptr<cql3::maps::literal> map) {
        if (!map || map->entries.empty()) {
            return std::unordered_map<sstring, sstring>{};
        }
        std::unordered_map<sstring, sstring> res{map->entries.size()};
        for (auto&& entry : map->entries) {
            // Because the parser tries to be smart and recover on error (to
            // allow displaying more than one error I suppose), we have null
            // entries in there. Just skip those, a proper error will be thrown in the end.
            if (!entry.first || !entry.second) {
                break;
            }
            auto left = dynamic_pointer_cast<cql3::constants::literal>(entry.first);
            if (!left) {
                sstring msg = "Invalid property name: " + entry.first->to_string();
                if (dynamic_pointer_cast<cql3::abstract_marker::raw>(entry.first)) {
                    msg += " (bind variables are not supported in DDL queries)";
                }
                add_recognition_error(msg);
                break;
            }
            auto right = dynamic_pointer_cast<cql3::constants::literal>(entry.second);
            if (!right) {
                sstring msg = "Invalid property value: " + entry.first->to_string() + " for property: " + entry.second->to_string();
                if (dynamic_pointer_cast<cql3::abstract_marker::raw>(entry.second)) {
                    msg += " (bind variables are not supported in DDL queries)";
                }
                add_recognition_error(msg);
                break;
            }
            res.emplace(left->get_raw_text(), right->get_raw_text());
        }
        return res;
    }

    void add_raw_update(std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>& operations,
        ::shared_ptr<cql3::column_identifier::raw> key, ::shared_ptr<cql3::operation::raw_update> update)
    {
        for (auto&& p : operations) {
            if (*p.first == *key && !p.second->is_compatible_with(update)) {
                // \%s is escaped for antlr
                add_recognition_error(sprint("Multiple incompatible setting of column \%s", *key));
            }
        }
        operations.emplace_back(std::move(key), std::move(update));
    }
}

@lexer::namespace{cql3_parser}

@lexer::traits {
    class CqlLexer;
    class CqlParser;
    typedef antlr3::Traits<CqlLexer, CqlParser> CqlLexerTraits;
    typedef CqlLexerTraits CqlParserTraits;
}

@lexer::header {
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
}

@lexer::context {
    using listener_type = cql3::error_listener<RecognizerType>;

    listener_type* listener;

    void set_error_listener(listener_type& listener) {
        this->listener = &listener;
    }

#if 0
    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
    {
        for (int i = 0, m = listeners.size(); i < m; i++)
            listeners.get(i).syntaxError(this, tokenNames, e);
    }
#endif
}

/** STATEMENTS **/

query returns [shared_ptr<parsed_statement> stmnt]
    : st=cqlStatement (';')* EOF { $stmnt = st; }
    ;

cqlStatement returns [shared_ptr<parsed_statement> stmt]
    @after{ if (stmt) { stmt->set_bound_variables(_bind_variables); } }
    : st1= selectStatement             { $stmt = st1; }
    | st2= insertStatement             { $stmt = st2; }
    | st3= updateStatement             { $stmt = st3; }
#if 0
    | st4= batchStatement              { $stmt = st4; }
#endif
    | st5= deleteStatement             { $stmt = st5; }
    | st6= useStatement                { $stmt = st6; }
#if 0
    | st7= truncateStatement           { $stmt = st7; }
#endif
    | st8= createKeyspaceStatement     { $stmt = st8; }
    | st9= createTableStatement        { $stmt = st9; }
#if 0
    | st10=createIndexStatement        { $stmt = st10; }
    | st11=dropKeyspaceStatement       { $stmt = st11; }
    | st12=dropTableStatement          { $stmt = st12; }
    | st13=dropIndexStatement          { $stmt = st13; }
    | st14=alterTableStatement         { $stmt = st14; }
    | st15=alterKeyspaceStatement      { $stmt = st15; }
    | st16=grantStatement              { $stmt = st16; }
    | st17=revokeStatement             { $stmt = st17; }
    | st18=listPermissionsStatement    { $stmt = st18; }
    | st19=createUserStatement         { $stmt = st19; }
    | st20=alterUserStatement          { $stmt = st20; }
    | st21=dropUserStatement           { $stmt = st21; }
    | st22=listUsersStatement          { $stmt = st22; }
    | st23=createTriggerStatement      { $stmt = st23; }
    | st24=dropTriggerStatement        { $stmt = st24; }
    | st25=createTypeStatement         { $stmt = st25; }
    | st26=alterTypeStatement          { $stmt = st26; }
    | st27=dropTypeStatement           { $stmt = st27; }
    | st28=createFunctionStatement     { $stmt = st28; }
    | st29=dropFunctionStatement       { $stmt = st29; }
    | st30=createAggregateStatement    { $stmt = st30; }
    | st31=dropAggregateStatement      { $stmt = st31; }
#endif
    ;

/*
 * USE <KEYSPACE>;
 */
useStatement returns [::shared_ptr<use_statement> stmt]
    : K_USE ks=keyspaceName { $stmt = ::make_shared<use_statement>(ks); }
    ;

/**
 * SELECT <expression>
 * FROM <CF>
 * WHERE KEY = "key1" AND COL > 1 AND COL < 100
 * LIMIT <NUMBER>;
 */
selectStatement returns [shared_ptr<select_statement::raw_statement> expr]
    @init {
        bool is_distinct = false;
        ::shared_ptr<cql3::term::raw> limit;
        select_statement::parameters::orderings_type orderings;
        bool allow_filtering = false;
    }
    : K_SELECT ( ( K_DISTINCT { is_distinct = true; } )?
                 sclause=selectClause
               | sclause=selectCountClause
               )
      K_FROM cf=columnFamilyName
      ( K_WHERE wclause=whereClause )?
      ( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] )* )?
      ( K_LIMIT rows=intValue { limit = rows; } )?
      ( K_ALLOW K_FILTERING  { allow_filtering = true; } )?
      {
          auto params = ::make_shared<select_statement::parameters>(std::move(orderings), is_distinct, allow_filtering);
          $expr = ::make_shared<select_statement::raw_statement>(std::move(cf), std::move(params),
            std::move(sclause), std::move(wclause), std::move(limit));
      }
    ;

selectClause returns [std::vector<shared_ptr<raw_selector>> expr]
    : t1=selector { $expr.push_back(t1); } (',' tN=selector { $expr.push_back(tN); })*
    | '*' { }
    ;

selector returns [shared_ptr<raw_selector> s]
    @init{ shared_ptr<cql3::column_identifier> alias; }
    : us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = make_shared<raw_selector>(us, alias); }
    ;

unaliasedSelector returns [shared_ptr<selectable::raw> s]
    @init { shared_ptr<selectable::raw> tmp; }
    :  ( c=cident                                  { tmp = c; }
#if 0
       | K_WRITETIME '(' c=cident ')'              { tmp = new Selectable.WritetimeOrTTL.Raw(c, true); }
       | K_TTL       '(' c=cident ')'              { tmp = new Selectable.WritetimeOrTTL.Raw(c, false); }
#endif
       | f=functionName args=selectionFunctionArgs { tmp = ::make_shared<selectable::with_function::raw>(std::move(f), std::move(args)); }
       )
#if 0
       ( '.' fi=cident { tmp = new Selectable.WithFieldSelection.Raw(tmp, fi); } )*
#endif
    { $s = tmp; }
    ;

selectionFunctionArgs returns [std::vector<shared_ptr<selectable::raw>> a]
    : '(' ')'
    | '(' s1=unaliasedSelector { a.push_back(std::move(s1)); }
          ( ',' sn=unaliasedSelector { a.push_back(std::move(sn)); } )*
      ')'
    ;

selectCountClause returns [std::vector<shared_ptr<raw_selector>> expr]
    @init{ auto alias = make_shared<cql3::column_identifier>("count", false); }
    : K_COUNT '(' countArgument ')' (K_AS c=ident { alias = c; })? {
        auto&& with_fn = ::make_shared<cql3::selection::selectable::with_function::raw>(
     	    cql3::functions::function_name::native_function("countRows"),
     	        std::vector<shared_ptr<cql3::selection::selectable::raw>>()); 
     	$expr.push_back(make_shared<cql3::selection::raw_selector>(with_fn, alias));
     }
    ;<commit_msg>cql3: enable WRITETIME and TTL functions<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

grammar Cql;

options {
    language = Cpp;
}

@parser::namespace{cql3_parser}

@lexer::includes {
#include "cql3/error_listener.hh"
}

@parser::includes {
#include "cql3/selection/writetime_or_ttl.hh"
#include "cql3/statements/create_keyspace_statement.hh"
#include "cql3/statements/create_table_statement.hh"
#include "cql3/statements/property_definitions.hh"
#include "cql3/statements/select_statement.hh"
#include "cql3/statements/update_statement.hh"
#include "cql3/statements/delete_statement.hh"
#include "cql3/statements/use_statement.hh"
#include "cql3/statements/ks_prop_defs.hh"
#include "cql3/selection/raw_selector.hh"
#include "cql3/constants.hh"
#include "cql3/operation_impl.hh"
#include "cql3/error_listener.hh"
#include "cql3/single_column_relation.hh"
#include "cql3/cql3_type.hh"
#include "cql3/cf_name.hh"
#include "cql3/maps.hh"
#include "cql3/sets.hh"
#include "cql3/lists.hh"
#include "cql3/functions/function_name.hh"
#include "cql3/functions/function_call.hh"
#include "core/sstring.hh"
#include "CqlLexer.hpp"

#include <unordered_map>
}

@parser::traits {
using namespace cql3::statements;
using namespace cql3::selection;
using cql3::cql3_type;
using conditions_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::column_condition::raw>>>;
using operations_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>;
}

@context {
    using listener_type = cql3::error_listener<RecognizerType>;
    listener_type* listener;

    std::vector<::shared_ptr<cql3::column_identifier>> _bind_variables;

#if 0
    public static final Set<String> reservedTypeNames = new HashSet<String>()
    {{
        add("byte");
        add("smallint");
        add("complex");
        add("enum");
        add("date");
        add("interval");
        add("macaddr");
        add("bitstring");
    }};
#endif

    shared_ptr<cql3::abstract_marker::raw> new_bind_variables(shared_ptr<cql3::column_identifier> name)
    {
        auto marker = make_shared<cql3::abstract_marker::raw>(_bind_variables.size());
        _bind_variables.push_back(name);
        return marker;
    }

#if 0
    public AbstractMarker.INRaw newINBindVariables(ColumnIdentifier name)
    {
        AbstractMarker.INRaw marker = new AbstractMarker.INRaw(bindVariables.size());
        bindVariables.add(name);
        return marker;
    }

    public Tuples.Raw newTupleBindVariables(ColumnIdentifier name)
    {
        Tuples.Raw marker = new Tuples.Raw(bindVariables.size());
        bindVariables.add(name);
        return marker;
    }

    public Tuples.INRaw newTupleINBindVariables(ColumnIdentifier name)
    {
        Tuples.INRaw marker = new Tuples.INRaw(bindVariables.size());
        bindVariables.add(name);
        return marker;
    }
#endif

    void set_error_listener(listener_type& listener) {
        this->listener = &listener;
    }

#if 0
    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
    {
        for (int i = 0, m = listeners.size(); i < m; i++)
            listeners.get(i).syntaxError(this, tokenNames, e);
    }
#endif

    void add_recognition_error(const sstring& msg) {
        listener->syntax_error(*this, msg);
    }

    std::unordered_map<sstring, sstring> convert_property_map(shared_ptr<cql3::maps::literal> map) {
        if (!map || map->entries.empty()) {
            return std::unordered_map<sstring, sstring>{};
        }
        std::unordered_map<sstring, sstring> res{map->entries.size()};
        for (auto&& entry : map->entries) {
            // Because the parser tries to be smart and recover on error (to
            // allow displaying more than one error I suppose), we have null
            // entries in there. Just skip those, a proper error will be thrown in the end.
            if (!entry.first || !entry.second) {
                break;
            }
            auto left = dynamic_pointer_cast<cql3::constants::literal>(entry.first);
            if (!left) {
                sstring msg = "Invalid property name: " + entry.first->to_string();
                if (dynamic_pointer_cast<cql3::abstract_marker::raw>(entry.first)) {
                    msg += " (bind variables are not supported in DDL queries)";
                }
                add_recognition_error(msg);
                break;
            }
            auto right = dynamic_pointer_cast<cql3::constants::literal>(entry.second);
            if (!right) {
                sstring msg = "Invalid property value: " + entry.first->to_string() + " for property: " + entry.second->to_string();
                if (dynamic_pointer_cast<cql3::abstract_marker::raw>(entry.second)) {
                    msg += " (bind variables are not supported in DDL queries)";
                }
                add_recognition_error(msg);
                break;
            }
            res.emplace(left->get_raw_text(), right->get_raw_text());
        }
        return res;
    }

    void add_raw_update(std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>& operations,
        ::shared_ptr<cql3::column_identifier::raw> key, ::shared_ptr<cql3::operation::raw_update> update)
    {
        for (auto&& p : operations) {
            if (*p.first == *key && !p.second->is_compatible_with(update)) {
                // \%s is escaped for antlr
                add_recognition_error(sprint("Multiple incompatible setting of column \%s", *key));
            }
        }
        operations.emplace_back(std::move(key), std::move(update));
    }
}

@lexer::namespace{cql3_parser}

@lexer::traits {
    class CqlLexer;
    class CqlParser;
    typedef antlr3::Traits<CqlLexer, CqlParser> CqlLexerTraits;
    typedef CqlLexerTraits CqlParserTraits;
}

@lexer::header {
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
}

@lexer::context {
    using listener_type = cql3::error_listener<RecognizerType>;

    listener_type* listener;

    void set_error_listener(listener_type& listener) {
        this->listener = &listener;
    }

#if 0
    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
    {
        for (int i = 0, m = listeners.size(); i < m; i++)
            listeners.get(i).syntaxError(this, tokenNames, e);
    }
#endif
}

/** STATEMENTS **/

query returns [shared_ptr<parsed_statement> stmnt]
    : st=cqlStatement (';')* EOF { $stmnt = st; }
    ;

cqlStatement returns [shared_ptr<parsed_statement> stmt]
    @after{ if (stmt) { stmt->set_bound_variables(_bind_variables); } }
    : st1= selectStatement             { $stmt = st1; }
    | st2= insertStatement             { $stmt = st2; }
    | st3= updateStatement             { $stmt = st3; }
#if 0
    | st4= batchStatement              { $stmt = st4; }
#endif
    | st5= deleteStatement             { $stmt = st5; }
    | st6= useStatement                { $stmt = st6; }
#if 0
    | st7= truncateStatement           { $stmt = st7; }
#endif
    | st8= createKeyspaceStatement     { $stmt = st8; }
    | st9= createTableStatement        { $stmt = st9; }
#if 0
    | st10=createIndexStatement        { $stmt = st10; }
    | st11=dropKeyspaceStatement       { $stmt = st11; }
    | st12=dropTableStatement          { $stmt = st12; }
    | st13=dropIndexStatement          { $stmt = st13; }
    | st14=alterTableStatement         { $stmt = st14; }
    | st15=alterKeyspaceStatement      { $stmt = st15; }
    | st16=grantStatement              { $stmt = st16; }
    | st17=revokeStatement             { $stmt = st17; }
    | st18=listPermissionsStatement    { $stmt = st18; }
    | st19=createUserStatement         { $stmt = st19; }
    | st20=alterUserStatement          { $stmt = st20; }
    | st21=dropUserStatement           { $stmt = st21; }
    | st22=listUsersStatement          { $stmt = st22; }
    | st23=createTriggerStatement      { $stmt = st23; }
    | st24=dropTriggerStatement        { $stmt = st24; }
    | st25=createTypeStatement         { $stmt = st25; }
    | st26=alterTypeStatement          { $stmt = st26; }
    | st27=dropTypeStatement           { $stmt = st27; }
    | st28=createFunctionStatement     { $stmt = st28; }
    | st29=dropFunctionStatement       { $stmt = st29; }
    | st30=createAggregateStatement    { $stmt = st30; }
    | st31=dropAggregateStatement      { $stmt = st31; }
#endif
    ;

/*
 * USE <KEYSPACE>;
 */
useStatement returns [::shared_ptr<use_statement> stmt]
    : K_USE ks=keyspaceName { $stmt = ::make_shared<use_statement>(ks); }
    ;

/**
 * SELECT <expression>
 * FROM <CF>
 * WHERE KEY = "key1" AND COL > 1 AND COL < 100
 * LIMIT <NUMBER>;
 */
selectStatement returns [shared_ptr<select_statement::raw_statement> expr]
    @init {
        bool is_distinct = false;
        ::shared_ptr<cql3::term::raw> limit;
        select_statement::parameters::orderings_type orderings;
        bool allow_filtering = false;
    }
    : K_SELECT ( ( K_DISTINCT { is_distinct = true; } )?
                 sclause=selectClause
               | sclause=selectCountClause
               )
      K_FROM cf=columnFamilyName
      ( K_WHERE wclause=whereClause )?
      ( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] )* )?
      ( K_LIMIT rows=intValue { limit = rows; } )?
      ( K_ALLOW K_FILTERING  { allow_filtering = true; } )?
      {
          auto params = ::make_shared<select_statement::parameters>(std::move(orderings), is_distinct, allow_filtering);
          $expr = ::make_shared<select_statement::raw_statement>(std::move(cf), std::move(params),
            std::move(sclause), std::move(wclause), std::move(limit));
      }
    ;

selectClause returns [std::vector<shared_ptr<raw_selector>> expr]
    : t1=selector { $expr.push_back(t1); } (',' tN=selector { $expr.push_back(tN); })*
    | '*' { }
    ;

selector returns [shared_ptr<raw_selector> s]
    @init{ shared_ptr<cql3::column_identifier> alias; }
    : us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = make_shared<raw_selector>(us, alias); }
    ;

unaliasedSelector returns [shared_ptr<selectable::raw> s]
    @init { shared_ptr<selectable::raw> tmp; }
    :  ( c=cident                                  { tmp = c; }
       | K_WRITETIME '(' c=cident ')'              { tmp = make_shared<selectable::writetime_or_ttl::raw>(c, true); }
       | K_TTL       '(' c=cident ')'              { tmp = make_shared<selectable::writetime_or_ttl::raw>(c, false); }
       | f=functionName args=selectionFunctionArgs { tmp = ::make_shared<selectable::with_function::raw>(std::move(f), std::move(args)); }
       )
#if 0
       ( '.' fi=cident { tmp = new Selectable.WithFieldSelection.Raw(tmp, fi); } )*
#endif
    { $s = tmp; }
    ;

selectionFunctionArgs returns [std::vector<shared_ptr<selectable::raw>> a]
    : '(' ')'
    | '(' s1=unaliasedSelector { a.push_back(std::move(s1)); }
          ( ',' sn=unaliasedSelector { a.push_back(std::move(sn)); } )*
      ')'
    ;

selectCountClause returns [std::vector<shared_ptr<raw_selector>> expr]
    @init{ auto alias = make_shared<cql3::column_identifier>("count", false); }
    : K_COUNT '(' countArgument ')' (K_AS c=ident { alias = c; })? {
        auto&& with_fn = ::make_shared<cql3::selection::selectable::with_function::raw>(
     	    cql3::functions::function_name::native_function("countRows"),
     	        std::vector<shared_ptr<cql3::selection::selectable::raw>>()); 
     	$expr.push_back(make_shared<cql3::selection::raw_selector>(with_fn, alias));
     }
    ;
{'fraction_non_alphanumeric': 0.13337359098228663, 'fraction_numerical': 0.014935587761674718, 'mean_word_length': 3.013085621970921, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 157, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6142910', 'n_tokens_mistral': 8083, 'n_tokens_neox': 7878, 'n_words': 1562}