@@ -913,7 +913,9 @@ module.exports = grammar({
913913
914914 select : ( $ ) =>
915915 seq (
916- $ . keyword_select ,
916+ completableKeyword ( $ , "select" , {
917+ minLength : 3 ,
918+ } ) ,
917919 seq ( optional ( $ . keyword_distinct ) , $ . select_expression )
918920 ) ,
919921
@@ -1086,7 +1088,10 @@ module.exports = grammar({
10861088 ) ,
10871089
10881090 reset_statement : ( $ ) =>
1089- seq ( $ . keyword_reset , choice ( $ . keyword_all , $ . any_identifier ) ) ,
1091+ seq (
1092+ completableKeyword ( $ , "reset" , { minLength : 3 } ) ,
1093+ choice ( $ . keyword_all , $ . any_identifier )
1094+ ) ,
10901095
10911096 _transaction_mode : ( $ ) =>
10921097 seq (
@@ -2994,7 +2999,7 @@ module.exports = grammar({
29942999 revoke_statement : ( $ ) =>
29953000 prec . left (
29963001 seq (
2997- $ . keyword_revoke ,
3002+ completableKeyword ( $ , "revoke" , { minLength : 3 } ) ,
29983003 optional (
29993004 choice (
30003005 seq ( $ . keyword_grant , $ . keyword_option , $ . keyword_for ) ,
@@ -3616,3 +3621,47 @@ function partialSeq(...rules) {
36163621
36173622 return prec . left ( finishedRule ) ;
36183623}
3624+
3625+ /**
3626+ *
3627+ * @typedef {Object } CompletableKeywordOpts
3628+ * @property {number } [minLength]
3629+ * @property {boolean } [unambiguous]
3630+ */
3631+
3632+ /**
3633+ * @param {RuleRecord } $
3634+ * @param {string } keyword
3635+ * @param {CompletableKeywordOpts } [opts={}]
3636+ */
3637+ function completableKeyword ( $ , keyword , opts = { } ) {
3638+ let matcher = "" ;
3639+
3640+ const minLength = opts . minLength ?? 1 ;
3641+ const unambiguous = opts . unambiguous ?? false ;
3642+
3643+ for ( let i = minLength ; i < keyword . length ; i ++ ) {
3644+ if ( matcher . length > 0 ) {
3645+ matcher += "|" ;
3646+ }
3647+
3648+ matcher += keyword . substring ( 0 , i ) ;
3649+ }
3650+
3651+ const reversedMatcher = matcher . split ( "|" ) . toReversed ( ) . join ( "|" ) ;
3652+ const partialMatch = new RegExp ( reversedMatcher , "ig" ) ;
3653+
3654+ const noMatchAlias = `partial_keyword:${ keyword } ` ;
3655+
3656+ const options = [ $ [ `keyword_${ keyword } ` ] , alias ( partialMatch , noMatchAlias ) ] ;
3657+
3658+ if ( unambiguous ) {
3659+ options . push ( alias ( new RegExp ( "REPLACED_TOKEN" , "i" ) , noMatchAlias ) ) ;
3660+
3661+ options . push (
3662+ alias ( new RegExp ( "REPLACED_TOKEN_WITH_QUOTE" , "i" ) , noMatchAlias )
3663+ ) ;
3664+ }
3665+
3666+ return choice ( ...options ) ;
3667+ }
0 commit comments