@@ -67,6 +67,28 @@ pub fn raw_dialect() -> Dialect {
67
67
// T-SQL supports square brackets for identifiers and @ for variables
68
68
dialect. insert_lexer_matchers (
69
69
vec ! [
70
+ // Compound comparison operators (must come before single character operators)
71
+ Matcher :: string( "tsql_ge" , ">=" , SyntaxKind :: RawComparisonOperator ) ,
72
+ Matcher :: string( "tsql_le" , "<=" , SyntaxKind :: RawComparisonOperator ) ,
73
+ Matcher :: string( "tsql_ne" , "!=" , SyntaxKind :: RawComparisonOperator ) ,
74
+ Matcher :: string( "tsql_ne_ansi" , "<>" , SyntaxKind :: RawComparisonOperator ) ,
75
+ Matcher :: string( "tsql_ngt" , "!>" , SyntaxKind :: RawComparisonOperator ) ,
76
+ Matcher :: string( "tsql_nlt" , "!<" , SyntaxKind :: RawComparisonOperator ) ,
77
+ // Compound assignment operators
78
+ Matcher :: string( "tsql_plusequals" , "+=" , SyntaxKind :: AssignmentOperator ) ,
79
+ Matcher :: string( "tsql_minusequals" , "-=" , SyntaxKind :: AssignmentOperator ) ,
80
+ Matcher :: string( "tsql_starequals" , "*=" , SyntaxKind :: AssignmentOperator ) ,
81
+ Matcher :: string( "tsql_slashequals" , "/=" , SyntaxKind :: AssignmentOperator ) ,
82
+ Matcher :: string( "tsql_percentequals" , "%=" , SyntaxKind :: AssignmentOperator ) ,
83
+ Matcher :: string( "tsql_ampersandequals" , "&=" , SyntaxKind :: AssignmentOperator ) ,
84
+ Matcher :: string( "tsql_pipeequals" , "|=" , SyntaxKind :: AssignmentOperator ) ,
85
+ Matcher :: string( "tsql_caretequals" , "^=" , SyntaxKind :: AssignmentOperator ) ,
86
+ // Unicode string literals
87
+ Matcher :: regex(
88
+ "tsql_unicode_string" ,
89
+ r"N'([^'\\]|\\.|'')*'" ,
90
+ SyntaxKind :: SingleQuote ,
91
+ ) ,
70
92
// Square brackets for identifiers: [Column Name]
71
93
Matcher :: regex(
72
94
"tsql_square_bracket_identifier" ,
@@ -217,15 +239,35 @@ pub fn raw_dialect() -> Dialect {
217
239
) ;
218
240
219
241
// Add T-SQL assignment operator segment
220
- dialect. add ( [ (
221
- "AssignmentOperatorSegment" . into ( ) ,
222
- NodeMatcher :: new (
223
- SyntaxKind :: AssignmentOperator ,
224
- Ref :: new ( "RawEqualsSegment" ) . to_matchable ( ) ,
225
- )
226
- . to_matchable ( )
227
- . into ( ) ,
228
- ) ] ) ;
242
+ dialect. add ( [
243
+ (
244
+ "AssignmentOperatorSegment" . into ( ) ,
245
+ NodeMatcher :: new (
246
+ SyntaxKind :: AssignmentOperator ,
247
+ one_of ( vec_of_erased ! [
248
+ Ref :: new( "RawEqualsSegment" ) ,
249
+ // Compound assignment operators
250
+ TypedParser :: new(
251
+ SyntaxKind :: AssignmentOperator ,
252
+ SyntaxKind :: AssignmentOperator
253
+ ) ,
254
+ ] )
255
+ . to_matchable ( ) ,
256
+ )
257
+ . to_matchable ( )
258
+ . into ( ) ,
259
+ ) ,
260
+ // Add raw segment definitions for compound assignment operators
261
+ (
262
+ "CompoundAssignmentOperatorSegment" . into ( ) ,
263
+ TypedParser :: new (
264
+ SyntaxKind :: AssignmentOperator ,
265
+ SyntaxKind :: AssignmentOperator ,
266
+ )
267
+ . to_matchable ( )
268
+ . into ( ) ,
269
+ ) ,
270
+ ] ) ;
229
271
230
272
// DECLARE statement for variable declarations
231
273
// Syntax: DECLARE @var1 INT = 10, @var2 VARCHAR(50) = 'text'
@@ -441,6 +483,8 @@ pub fn raw_dialect() -> Dialect {
441
483
Ref :: new( "WhileStatementGrammar" ) ,
442
484
Ref :: new( "BatchSeparatorGrammar" ) ,
443
485
Ref :: new( "UseStatementGrammar" ) ,
486
+ Ref :: new( "CreateProcedureStatementSegment" ) ,
487
+ Ref :: new( "CreateTypeStatementSegment" ) ,
444
488
// Include all ANSI statement types
445
489
Ref :: new( "SelectableGrammar" ) ,
446
490
Ref :: new( "MergeStatementSegment" ) ,
@@ -843,6 +887,220 @@ pub fn raw_dialect() -> Dialect {
843
887
. into ( ) ,
844
888
) ] ) ;
845
889
890
+ // T-SQL IDENTITY column constraint
891
+ dialect. add ( [ (
892
+ "IdentityGrammar" . into ( ) ,
893
+ Sequence :: new ( vec_of_erased ! [
894
+ Ref :: keyword( "IDENTITY" ) ,
895
+ Bracketed :: new( vec_of_erased![
896
+ Ref :: new( "NumericLiteralSegment" ) , // seed
897
+ Ref :: new( "CommaSegment" ) ,
898
+ Ref :: new( "NumericLiteralSegment" ) // increment
899
+ ] )
900
+ . config( |this| this. optional( ) )
901
+ ] )
902
+ . to_matchable ( )
903
+ . into ( ) ,
904
+ ) ] ) ;
905
+
906
+ // Override ColumnConstraintSegment to add IDENTITY support
907
+ dialect. replace_grammar (
908
+ "ColumnConstraintSegment" ,
909
+ NodeMatcher :: new (
910
+ SyntaxKind :: ColumnConstraintSegment ,
911
+ Sequence :: new ( vec_of_erased ! [
912
+ Sequence :: new( vec_of_erased![
913
+ Ref :: keyword( "CONSTRAINT" ) ,
914
+ Ref :: new( "ObjectReferenceSegment" ) , // Constraint name
915
+ ] )
916
+ . config( |this| this. optional( ) ) ,
917
+ one_of( vec_of_erased![
918
+ Sequence :: new( vec_of_erased![
919
+ Ref :: keyword( "NOT" ) . optional( ) ,
920
+ Ref :: keyword( "NULL" ) ,
921
+ ] ) ,
922
+ Sequence :: new( vec_of_erased![
923
+ Ref :: keyword( "CHECK" ) ,
924
+ Bracketed :: new( vec_of_erased![ Ref :: new( "ExpressionSegment" ) ] ) ,
925
+ ] ) ,
926
+ Sequence :: new( vec_of_erased![
927
+ Ref :: keyword( "DEFAULT" ) ,
928
+ Ref :: new( "ColumnConstraintDefaultGrammar" ) ,
929
+ ] ) ,
930
+ Ref :: new( "PrimaryKeyGrammar" ) ,
931
+ Ref :: new( "UniqueKeyGrammar" ) ,
932
+ Ref :: new( "AutoIncrementGrammar" ) ,
933
+ Ref :: new( "ReferenceDefinitionGrammar" ) ,
934
+ Ref :: new( "CommentClauseSegment" ) ,
935
+ Sequence :: new( vec_of_erased![
936
+ Ref :: keyword( "COLLATE" ) ,
937
+ Ref :: new( "CollationReferenceSegment" ) ,
938
+ ] ) ,
939
+ // T-SQL IDENTITY
940
+ Ref :: new( "IdentityGrammar" ) ,
941
+ ] ) ,
942
+ ] )
943
+ . to_matchable ( ) ,
944
+ )
945
+ . to_matchable ( ) ,
946
+ ) ;
947
+
948
+ // Override TableReferenceSegment to support temporary tables starting with #
949
+ dialect. replace_grammar (
950
+ "TableReferenceSegment" ,
951
+ one_of ( vec_of_erased ! [
952
+ // Temporary tables
953
+ Sequence :: new( vec_of_erased![
954
+ StringParser :: new( "#" , SyntaxKind :: Word ) ,
955
+ Ref :: new( "SingleIdentifierGrammar" )
956
+ ] )
957
+ . allow_gaps( false ) ,
958
+ // Global temporary tables
959
+ Sequence :: new( vec_of_erased![
960
+ StringParser :: new( "##" , SyntaxKind :: Word ) ,
961
+ Ref :: new( "SingleIdentifierGrammar" )
962
+ ] )
963
+ . allow_gaps( false ) ,
964
+ // Regular tables
965
+ Ref :: new( "ObjectReferenceSegment" ) ,
966
+ // Table variables
967
+ Ref :: new( "TsqlVariableSegment" ) ,
968
+ ] )
969
+ . to_matchable ( ) ,
970
+ ) ;
971
+
972
+ // Override CREATE TABLE to support T-SQL specific syntax
973
+ dialect. replace_grammar (
974
+ "CreateTableStatementSegment" ,
975
+ NodeMatcher :: new (
976
+ SyntaxKind :: CreateTableStatement ,
977
+ Sequence :: new ( vec_of_erased ! [
978
+ Ref :: keyword( "CREATE" ) ,
979
+ Ref :: keyword( "TABLE" ) ,
980
+ Ref :: new( "TableReferenceSegment" ) ,
981
+ one_of( vec_of_erased![
982
+ // Columns and constraints
983
+ Sequence :: new( vec_of_erased![
984
+ Bracketed :: new( vec_of_erased![ Delimited :: new( vec_of_erased![ one_of(
985
+ vec_of_erased![
986
+ Ref :: new( "TableConstraintSegment" ) ,
987
+ Ref :: new( "ColumnDefinitionSegment" )
988
+ ]
989
+ ) ] ) ] ) ,
990
+ Ref :: new( "CommentClauseSegment" ) . optional( )
991
+ ] ) ,
992
+ // CREATE TABLE AS syntax
993
+ Sequence :: new( vec_of_erased![
994
+ Ref :: keyword( "AS" ) ,
995
+ optionally_bracketed( vec_of_erased![ Ref :: new( "SelectableGrammar" ) ] )
996
+ ] ) ,
997
+ ] )
998
+ ] )
999
+ . to_matchable ( ) ,
1000
+ )
1001
+ . to_matchable ( ) ,
1002
+ ) ;
1003
+
1004
+ // T-SQL CREATE FUNCTION support
1005
+ dialect. replace_grammar (
1006
+ "CreateFunctionStatementSegment" ,
1007
+ NodeMatcher :: new (
1008
+ SyntaxKind :: CreateFunctionStatement ,
1009
+ Sequence :: new ( vec_of_erased ! [
1010
+ Ref :: keyword( "CREATE" ) ,
1011
+ Ref :: keyword( "FUNCTION" ) ,
1012
+ Ref :: new( "FunctionNameSegment" ) ,
1013
+ Ref :: new( "FunctionParameterListGrammar" ) ,
1014
+ Ref :: keyword( "RETURNS" ) ,
1015
+ one_of( vec_of_erased![
1016
+ // Scalar function: RETURNS datatype
1017
+ Ref :: new( "DatatypeSegment" ) ,
1018
+ // Table-valued function: RETURNS TABLE
1019
+ Ref :: keyword( "TABLE" ) ,
1020
+ // Multi-statement table-valued function: RETURNS @variable TABLE (...)
1021
+ Sequence :: new( vec_of_erased![
1022
+ Ref :: new( "TsqlVariableSegment" ) ,
1023
+ Ref :: keyword( "TABLE" ) ,
1024
+ Bracketed :: new( vec_of_erased![ Delimited :: new( vec_of_erased![ Ref :: new(
1025
+ "ColumnDefinitionSegment"
1026
+ ) ] ) ] )
1027
+ ] )
1028
+ ] ) ,
1029
+ Ref :: keyword( "AS" ) ,
1030
+ one_of( vec_of_erased![
1031
+ // Inline table-valued function
1032
+ Ref :: keyword( "RETURN" ) ,
1033
+ // Multi-statement function with BEGIN...END
1034
+ Ref :: new( "BeginEndBlockGrammar" )
1035
+ ] )
1036
+ ] )
1037
+ . to_matchable ( ) ,
1038
+ )
1039
+ . to_matchable ( ) ,
1040
+ ) ;
1041
+
1042
+ // T-SQL CREATE PROCEDURE support
1043
+ dialect. add ( [ (
1044
+ "CreateProcedureStatementSegment" . into ( ) ,
1045
+ NodeMatcher :: new (
1046
+ SyntaxKind :: Statement ,
1047
+ Sequence :: new ( vec_of_erased ! [
1048
+ Ref :: keyword( "CREATE" ) ,
1049
+ one_of( vec_of_erased![
1050
+ Ref :: keyword( "PROCEDURE" ) ,
1051
+ Ref :: keyword( "PROC" )
1052
+ ] ) ,
1053
+ Ref :: new( "ObjectReferenceSegment" ) ,
1054
+ // Parameters (optional)
1055
+ Sequence :: new( vec_of_erased![
1056
+ Delimited :: new( vec_of_erased![ Sequence :: new( vec_of_erased![
1057
+ Ref :: new( "TsqlVariableSegment" ) ,
1058
+ Ref :: new( "DatatypeSegment" ) ,
1059
+ // Optional default value
1060
+ Sequence :: new( vec_of_erased![
1061
+ Ref :: new( "EqualsSegment" ) ,
1062
+ Ref :: new( "LiteralGrammar" )
1063
+ ] )
1064
+ . config( |this| this. optional( ) ) ,
1065
+ // Optional OUTPUT keyword
1066
+ Ref :: keyword( "OUTPUT" ) . optional( )
1067
+ ] ) ] )
1068
+ . config( |this| this. optional( ) )
1069
+ ] )
1070
+ . config( |this| this. optional( ) ) ,
1071
+ Ref :: keyword( "AS" ) ,
1072
+ Ref :: new( "BeginEndBlockGrammar" )
1073
+ ] )
1074
+ . to_matchable ( ) ,
1075
+ )
1076
+ . to_matchable ( )
1077
+ . into ( ) ,
1078
+ ) ] ) ;
1079
+
1080
+ // T-SQL CREATE TYPE support for table types
1081
+ dialect. add ( [ (
1082
+ "CreateTypeStatementSegment" . into ( ) ,
1083
+ NodeMatcher :: new (
1084
+ SyntaxKind :: CreateTypeStatement ,
1085
+ Sequence :: new ( vec_of_erased ! [
1086
+ Ref :: keyword( "CREATE" ) ,
1087
+ Ref :: keyword( "TYPE" ) ,
1088
+ Ref :: new( "ObjectReferenceSegment" ) ,
1089
+ Ref :: keyword( "AS" ) ,
1090
+ Ref :: keyword( "TABLE" ) ,
1091
+ Bracketed :: new( vec_of_erased![ Delimited :: new( vec_of_erased![ one_of(
1092
+ vec_of_erased![
1093
+ Ref :: new( "TableConstraintSegment" ) ,
1094
+ Ref :: new( "ColumnDefinitionSegment" )
1095
+ ]
1096
+ ) ] ) ] )
1097
+ ] )
1098
+ . to_matchable ( ) ,
1099
+ )
1100
+ . to_matchable ( )
1101
+ . into ( ) ,
1102
+ ) ] ) ;
1103
+
846
1104
// expand() must be called after all grammar modifications
847
1105
848
1106
dialect
0 commit comments