@@ -114,17 +114,57 @@ func (l *Lexer) skipUntil(val rune) {
114114 }
115115}
116116
117- func (l * Lexer ) consumeIdent () {
118- for ! l .done () && ! l .isEndIdent (l .next ()) {
117+ func isNamedParamStart (r rune ) bool {
118+ return r == '_' || unicode .IsLetter (r )
119+ }
120+
121+ func isNamedParamPart (r rune ) bool {
122+ return r == '_' || unicode .IsLetter (r ) || unicode .IsDigit (r )
123+ }
124+
125+ func isNamedParamBoundary (r rune ) bool {
126+ return ! (r == '_' || unicode .IsLetter (r ) || unicode .IsDigit (r ) || r == '"' )
127+ }
128+
129+ func (l * Lexer ) currentRuneStart () int {
130+ if l .width == 0 {
131+ return l .pos
132+ }
133+ return l .pos - l .width
134+ }
135+
136+ func (l * Lexer ) shouldLexNamedParam () bool {
137+ at := l .currentRuneStart ()
138+ if at < 0 || at >= len (l .input ) || l .input [at ] != '@' {
139+ return false
119140 }
141+
142+ nextPos := at + len ("@" )
143+ if nextPos >= len (l .input ) {
144+ return false
145+ }
146+
147+ next , _ := utf8 .DecodeRuneInString (l .input [nextPos :])
148+ if ! isNamedParamStart (next ) {
149+ return false
150+ }
151+
152+ if at == 0 {
153+ return true
154+ }
155+
156+ prev , _ := utf8 .DecodeLastRuneInString (l .input [:at ])
157+ return isNamedParamBoundary (prev )
120158}
121159
122- func (l * Lexer ) isEndIdent (r rune ) bool {
123- shouldEnd := unicode .IsSpace (r ) || strings .ContainsRune (",)" , r )
124- if shouldEnd {
125- l .backup ()
160+ func (l * Lexer ) consumeNamedParam () {
161+ for ! l .done () {
162+ r := l .next ()
163+ if ! isNamedParamPart (r ) {
164+ l .backup ()
165+ return
166+ }
126167 }
127- return shouldEnd
128168}
129169
130170func (l * Lexer ) next () rune {
@@ -174,7 +214,7 @@ func lexQuery(l *Lexer) stateFunc {
174214 return lexString
175215 }
176216
177- if r == '@' {
217+ if r == '@' && l . shouldLexNamedParam () {
178218 return lexNamedParam
179219 }
180220
@@ -220,8 +260,8 @@ func lexNamedParam(l *Lexer) stateFunc {
220260 l .writeChunk ()
221261 l .next ()
222262 l .start = l .pos
223- // advance through the name
224- l .consumeIdent ()
263+ // advance through a valid named-parameter token
264+ l .consumeNamedParam ()
225265 l .onNamed (strings .ToUpper (l .input [l .start :l .pos ]))
226266 l .start = l .pos
227267 l .output .WriteRune ('?' )
0 commit comments