1use std::borrow::Cow;
10use std::fmt;
11
12use rupg_common::SqlState;
13
14use crate::error::{Error, Notice, Severity};
15use crate::generated::keywords::{self, Keyword};
16use crate::generated::tables::token;
17use crate::parser::character;
18
19pub(crate) const NAME_LENGTH: usize = 63;
21
22const UNDEFINED: u16 = 2;
24
25#[derive(Clone, Debug)]
27pub enum Value<'a> {
28 None,
30 Integer(i32),
32 Text(Cow<'a, str>),
34 Keyword(&'static Keyword),
36}
37
38impl PartialEq for Value<'_> {
39 fn eq(&self, other: &Self) -> bool {
40 match (self, other) {
41 (Value::None, Value::None) => true,
42 (Value::Integer(a), Value::Integer(b)) => a == b,
43 (Value::Text(a), Value::Text(b)) => a == b,
44 (Value::Keyword(a), Value::Keyword(b)) => std::ptr::eq(*a, *b),
45 _ => false,
46 }
47 }
48}
49
50#[derive(Clone, Debug, PartialEq)]
52pub struct Token<'a> {
53 pub kind: u16,
55 pub start: usize,
57 pub end: usize,
59 pub value: Value<'a>,
61}
62
63impl Token<'_> {
64 pub fn text(&self) -> Option<&str> {
66 match &self.value {
67 Value::Text(text) => Some(text),
68 _ => None,
69 }
70 }
71}
72
73#[derive(Clone, Copy, PartialEq, Eq)]
75enum Quote {
76 Bit,
78 Hex,
80 Plain,
82 Escape,
84 Unicode,
86}
87
88pub struct Lexer<'a> {
90 text: &'a str,
91 bytes: &'a [u8],
92 at: usize,
93 notices: Vec<Notice>,
94}
95
96impl fmt::Debug for Lexer<'_> {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 f.debug_struct("Lexer").field("at", &self.at).finish_non_exhaustive()
99 }
100}
101
102struct Literal {
104 start: usize,
105 end: usize,
106 copy: Option<Vec<u8>>,
107}
108
109impl Literal {
110 fn new() -> Literal {
111 Literal { start: 0, end: 0, copy: None }
112 }
113
114 fn copy(&mut self, bytes: &[u8]) -> &mut Vec<u8> {
115 self.copy.get_or_insert_with(|| bytes[self.start..self.end].to_vec())
116 }
117
118 fn push(&mut self, bytes: &[u8], from: usize, to: usize) {
120 if self.copy.is_none() {
121 if self.start == self.end {
122 (self.start, self.end) = (from, to);
123 return;
124 }
125 if self.end == from {
126 self.end = to;
127 return;
128 }
129 }
130 self.copy(bytes).extend_from_slice(&bytes[from..to]);
131 }
132
133 fn push_byte(&mut self, bytes: &[u8], b: u8) {
134 self.copy(bytes).push(b);
135 }
136
137 fn push_char(&mut self, bytes: &[u8], c: char) {
138 let mut buffer = [0; 4];
139 self.copy(bytes).extend_from_slice(c.encode_utf8(&mut buffer).as_bytes());
140 }
141
142 fn is_empty(&self) -> bool {
143 match &self.copy {
144 Some(copy) => copy.is_empty(),
145 None => self.start == self.end,
146 }
147 }
148
149 fn finish<'a>(self, text: &'a str, verify: bool) -> Result<Cow<'a, str>, Error> {
151 let Some(copy) = self.copy else {
152 return Ok(Cow::Borrowed(&text[self.start..self.end]));
153 };
154 if verify && let Some(zero) = copy.iter().position(|&b| b == 0) {
155 let valid = std::str::from_utf8(©).map_or_else(|e| e.valid_up_to(), str::len);
156 return Err(Error::encoding(©[zero.min(valid)..]));
157 }
158 String::from_utf8(copy).map(Cow::Owned).map_err(|e| {
159 let at = e.utf8_error().valid_up_to();
160 Error::encoding(&e.as_bytes()[at..])
161 })
162 }
163}
164
165fn is_space(b: u8) -> bool {
166 matches!(b, b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c)
167}
168
169fn is_ident_start(b: u8) -> bool {
171 b.is_ascii_alphabetic() || b == b'_' || b >= 0x80
172}
173
174fn is_dolq_cont(b: u8) -> bool {
176 is_ident_start(b) || b.is_ascii_digit()
177}
178
179fn is_ident_cont(b: u8) -> bool {
181 is_dolq_cont(b) || b == b'$'
182}
183
184fn is_op_char(b: u8) -> bool {
186 matches!(
187 b,
188 b'~' | b'!'
189 | b'@'
190 | b'#'
191 | b'^'
192 | b'&'
193 | b'|'
194 | b'`'
195 | b'?'
196 | b'+'
197 | b'-'
198 | b'*'
199 | b'/'
200 | b'%'
201 | b'<'
202 | b'>'
203 | b'='
204 )
205}
206
207fn is_self(b: u8) -> bool {
209 matches!(
210 b,
211 b',' | b'('
212 | b')'
213 | b'['
214 | b']'
215 | b'.'
216 | b';'
217 | b':'
218 | b'+'
219 | b'-'
220 | b'*'
221 | b'/'
222 | b'%'
223 | b'^'
224 | b'<'
225 | b'>'
226 | b'='
227 )
228}
229
230fn is_first_surrogate(c: u32) -> bool {
231 (0xd800..=0xdbff).contains(&c)
232}
233
234fn is_second_surrogate(c: u32) -> bool {
235 (0xdc00..=0xdfff).contains(&c)
236}
237
238fn surrogate_pair(first: u32, second: u32) -> u32 {
239 ((first & 0x3ff) << 10) + (second & 0x3ff) + 0x10000
240}
241
242fn hex_value(digits: &[u8]) -> u32 {
244 digits.iter().fold(0, |value, &d| (value << 4) | char::from(d).to_digit(16).unwrap_or(0))
245}
246
247fn integer(text: &[u8]) -> Option<i32> {
249 let (radix, digits) = match text {
250 [b'0', b'x' | b'X', rest @ ..] => (16, rest),
251 [b'0', b'o' | b'O', rest @ ..] => (8, rest),
252 [b'0', b'b' | b'B', rest @ ..] => (2, rest),
253 _ => (10, text),
254 };
255 let mut value: i32 = 0;
256 for &d in digits {
257 if d == b'_' {
258 continue;
259 }
260 let digit = char::from(d).to_digit(radix)?;
261 value = value.checked_mul(radix as i32)?.checked_add(digit as i32)?;
262 }
263 Some(value)
264}
265
266fn downcase(word: &str) -> Cow<'_, str> {
268 if word.bytes().any(|b| b.is_ascii_uppercase()) {
269 Cow::Owned(word.to_ascii_lowercase())
270 } else {
271 Cow::Borrowed(word)
272 }
273}
274
275pub(crate) fn truncate<'a>(name: Cow<'a, str>, notices: &mut Vec<Notice>) -> Cow<'a, str> {
277 if name.len() <= NAME_LENGTH {
278 return name;
279 }
280 let mut length = NAME_LENGTH;
281 while !name.is_char_boundary(length) {
282 length -= 1;
283 }
284 notices.push(Notice {
285 severity: Severity::Notice,
286 code: SqlState::NAME_TOO_LONG,
287 message: format!("identifier \"{name}\" will be truncated to \"{}\"", &name[..length]),
288 location: None,
289 });
290 match name {
291 Cow::Borrowed(name) => Cow::Borrowed(&name[..length]),
292 Cow::Owned(mut name) => {
293 name.truncate(length);
294 Cow::Owned(name)
295 }
296 }
297}
298
299impl<'a> Lexer<'a> {
300 pub fn new(text: &'a str) -> Lexer<'a> {
302 let text = text.find('\0').map_or(text, |zero| &text[..zero]);
303 Lexer { text, bytes: text.as_bytes(), at: 0, notices: Vec::new() }
304 }
305
306 pub fn text(&self) -> &'a str {
308 self.text
309 }
310
311 pub fn take_notices(&mut self) -> Vec<Notice> {
313 std::mem::take(&mut self.notices)
314 }
315
316 pub(crate) fn notices(&mut self) -> &mut Vec<Notice> {
317 &mut self.notices
318 }
319
320 fn byte(&self, i: usize) -> u8 {
322 self.bytes.get(i).copied().unwrap_or(0)
323 }
324
325 fn syntax(&self, message: &str, start: usize, end: usize) -> Error {
326 Error::syntax(self.bytes, message, start, end)
327 }
328
329 fn emit(&mut self, kind: u16, start: usize, end: usize, value: Value<'a>) -> Token<'a> {
330 self.at = end;
331 Token { kind, start, end, value }
332 }
333
334 pub fn next_token(&mut self) -> Result<Token<'a>, Error> {
336 self.skip()?;
337 let start = self.at;
338 let c = self.byte(start);
339 let n = self.byte(start + 1);
340 match c {
341 _ if start >= self.bytes.len() => Ok(self.emit(0, start, start, Value::None)),
342 b'\'' => self.quoted(Quote::Plain, start, start + 1),
343 b'"' => self.delimited(token::IDENT, start, start + 1),
344 b'$' => self.dollar(start),
345 b'0'..=b'9' => self.number(start),
346 b'.' if n.is_ascii_digit() => self.number(start),
347 b'.' if n == b'.' => Ok(self.emit(token::DOT_DOT, start, start + 2, Value::None)),
348 b':' if n == b':' => Ok(self.emit(token::TYPECAST, start, start + 2, Value::None)),
349 b':' if n == b'=' => Ok(self.emit(token::COLON_EQUALS, start, start + 2, Value::None)),
350 b'b' | b'B' if n == b'\'' => self.quoted(Quote::Bit, start, start + 2),
351 b'x' | b'X' if n == b'\'' => self.quoted(Quote::Hex, start, start + 2),
352 b'e' | b'E' if n == b'\'' => self.quoted(Quote::Escape, start, start + 2),
353 b'n' | b'N' if n == b'\'' => {
354 let nchar = keywords::lookup(b"nchar");
356 let kind = nchar.map_or(token::NCHAR, |k| k.token);
357 let value = nchar.map_or(Value::None, Value::Keyword);
358 Ok(self.emit(kind, start, start + 1, value))
359 }
360 b'u' | b'U' if n == b'&' => match self.byte(start + 2) {
361 b'\'' => self.quoted(Quote::Unicode, start, start + 3),
362 b'"' => self.delimited(token::UIDENT, start, start + 3),
363 _ => {
365 let value = Value::Text(downcase(&self.text[start..start + 1]));
366 Ok(self.emit(token::IDENT, start, start + 1, value))
367 }
368 },
369 _ if is_ident_start(c) => Ok(self.identifier(start)),
370 _ if is_op_char(c) => self.operator(start),
371 _ => {
373 let kind = character(c).unwrap_or(UNDEFINED);
374 Ok(self.emit(kind, start, start + 1, Value::None))
375 }
376 }
377 }
378
379 fn skip(&mut self) -> Result<(), Error> {
381 loop {
382 match self.byte(self.at) {
383 b if is_space(b) && self.at < self.bytes.len() => self.at += 1,
384 b'-' if self.byte(self.at + 1) == b'-' => self.at = self.line_end(self.at),
385 b'/' if self.byte(self.at + 1) == b'*' => self.comment()?,
386 _ => return Ok(()),
387 }
388 }
389 }
390
391 fn line_end(&self, from: usize) -> usize {
393 self.bytes[from..]
394 .iter()
395 .position(|&b| b == b'\n' || b == b'\r')
396 .map_or(self.bytes.len(), |at| from + at)
397 }
398
399 fn comment(&mut self) -> Result<(), Error> {
401 let start = self.at;
402 let mut depth = 0usize;
403 let mut i = start + 2;
404 loop {
405 if i >= self.bytes.len() {
406 return Err(self.syntax("unterminated /* comment", start, i));
407 }
408 match (self.bytes[i], self.byte(i + 1)) {
409 (b'/', b'*') => {
410 depth += 1;
411 i += 2;
412 }
413 (b'*', b'/') => {
414 if depth == 0 {
415 self.at = i + 2;
416 return Ok(());
417 }
418 depth -= 1;
419 i += 2;
420 }
421 _ => i += 1,
422 }
423 }
424 }
425
426 fn continuation(&self, mut i: usize) -> Option<usize> {
428 let mut newline = false;
429 loop {
430 match self.byte(i) {
431 b' ' | b'\t' | 0x0b | 0x0c => i += 1,
432 b'\n' | b'\r' => {
433 newline = true;
434 i += 1;
435 }
436 b'-' if self.byte(i + 1) == b'-' => i = self.line_end(i),
437 b'\'' if newline => return Some(i + 1),
438 _ => return None,
439 }
440 }
441 }
442
443 fn quoted(&mut self, quote: Quote, start: usize, open: usize) -> Result<Token<'a>, Error> {
445 let bytes = self.bytes;
446 let mut literal = Literal::new();
447 match quote {
448 Quote::Bit => literal.push_byte(bytes, b'b'),
449 Quote::Hex => literal.push_byte(bytes, b'x'),
450 _ => {}
451 }
452 let mut verify = false;
453 let mut i = open;
454 let end = loop {
455 if i >= bytes.len() {
456 let message = match quote {
457 Quote::Bit => "unterminated bit string literal",
458 Quote::Hex => "unterminated hexadecimal string literal",
459 _ => "unterminated quoted string",
460 };
461 return Err(self.syntax(message, start, i));
462 }
463 match bytes[i] {
464 b'\'' if self.byte(i + 1) == b'\'' && !matches!(quote, Quote::Bit | Quote::Hex) => {
466 literal.push(bytes, i, i + 1);
467 i += 2;
468 }
469 b'\'' => match self.continuation(i + 1) {
470 Some(next) => i = next,
471 None => break i + 1,
472 },
473 b'\\' if quote == Quote::Escape => {
474 i = self.escape(i, &mut literal, &mut verify)?;
475 }
476 _ => {
477 let stop = |&b: &u8| b == b'\'' || (b == b'\\' && quote == Quote::Escape);
478 let run = bytes[i..].iter().position(stop).map_or(bytes.len(), |n| i + n);
479 literal.push(bytes, i, run);
480 i = run;
481 }
482 }
483 };
484 let kind = match quote {
485 Quote::Bit => token::BCONST,
486 Quote::Hex => token::XCONST,
487 Quote::Plain | Quote::Escape => token::SCONST,
488 Quote::Unicode => token::USCONST,
489 };
490 let text = literal.finish(self.text, verify)?;
491 Ok(self.emit(kind, start, end, Value::Text(text)))
492 }
493
494 fn escape(&self, i: usize, literal: &mut Literal, verify: &mut bool) -> Result<usize, Error> {
496 let bytes = self.bytes;
497 let n = self.byte(i + 1);
498 if i + 1 >= bytes.len() {
499 literal.push_byte(bytes, b'\\');
501 return Ok(i + 1);
502 }
503 let mut byte = |b: u8, literal: &mut Literal| {
504 literal.push_byte(bytes, b);
505 if b == 0 || b >= 0x80 {
506 *verify = true;
507 }
508 };
509 match n {
510 b'0'..=b'7' => {
511 let digits =
512 bytes[i + 1..].iter().take(3).take_while(|b| (b'0'..=b'7').contains(b));
513 let length = digits.clone().count();
514 let value = digits.fold(0u32, |v, &d| (v << 3) | u32::from(d - b'0'));
516 byte((value & 0xff) as u8, literal);
517 Ok(i + 1 + length)
518 }
519 b'x' if self.byte(i + 2).is_ascii_hexdigit() => {
520 let length = if self.byte(i + 3).is_ascii_hexdigit() { 2 } else { 1 };
521 byte(hex_value(&bytes[i + 2..i + 2 + length]) as u8, literal);
522 Ok(i + 2 + length)
523 }
524 b'u' | b'U' => {
525 let (c, after) = self.unicode(i)?;
526 let c = if is_first_surrogate(c) {
527 if self.byte(after) != b'\\' || !matches!(self.byte(after + 1), b'u' | b'U') {
529 let end = (after + 1).min(bytes.len());
530 return Err(self.syntax("invalid Unicode surrogate pair", after, end));
531 }
532 let (second, end) = self.unicode(after)?;
533 if !is_second_surrogate(second) {
534 return Err(self.syntax("invalid Unicode surrogate pair", after, end));
535 }
536 return self.push_unicode(surrogate_pair(c, second), after, end, literal);
537 } else if is_second_surrogate(c) {
538 return Err(self.syntax("invalid Unicode surrogate pair", i, after));
539 } else {
540 c
541 };
542 self.push_unicode(c, i, after, literal)
543 }
544 _ => {
545 let value = match n {
547 b'b' => 0x08,
548 b'f' => 0x0c,
549 b'n' => b'\n',
550 b'r' => b'\r',
551 b't' => b'\t',
552 b'v' => 0x0b,
553 _ => n,
554 };
555 byte(value, literal);
556 Ok(i + 2)
557 }
558 }
559 }
560
561 fn unicode(&self, i: usize) -> Result<(u32, usize), Error> {
563 let length = if self.byte(i + 1) == b'u' { 4 } else { 8 };
564 let digits = &self.bytes[i + 2..];
565 if digits.len() < length || !digits[..length].iter().all(u8::is_ascii_hexdigit) {
566 return Err(Error {
567 code: SqlState::INVALID_ESCAPE_SEQUENCE,
568 message: "invalid Unicode escape".to_owned(),
569 detail: None,
570 hint: Some("Unicode escapes must be \\uXXXX or \\UXXXXXXXX."),
571 location: Some(i),
572 });
573 }
574 Ok((hex_value(&digits[..length]), i + 2 + length))
575 }
576
577 fn push_unicode(
579 &self,
580 c: u32,
581 start: usize,
582 end: usize,
583 literal: &mut Literal,
584 ) -> Result<usize, Error> {
585 match char::from_u32(c).filter(|&c| c != '\0') {
586 Some(c) => {
587 literal.push_char(self.bytes, c);
588 Ok(end)
589 }
590 None => Err(self.syntax("invalid Unicode escape value", start, end)),
591 }
592 }
593
594 fn delimited(&mut self, kind: u16, start: usize, open: usize) -> Result<Token<'a>, Error> {
596 let bytes = self.bytes;
597 let mut literal = Literal::new();
598 let mut i = open;
599 let end = loop {
600 if i >= bytes.len() {
601 return Err(self.syntax("unterminated quoted identifier", start, i));
602 }
603 if bytes[i] == b'"' {
604 if self.byte(i + 1) != b'"' {
605 break i + 1;
606 }
607 literal.push(bytes, i, i + 1);
608 i += 2;
609 } else {
610 let run = bytes[i..].iter().position(|&b| b == b'"').map_or(bytes.len(), |n| i + n);
611 literal.push(bytes, i, run);
612 i = run;
613 }
614 };
615 if literal.is_empty() {
616 return Err(self.syntax("zero-length delimited identifier", start, end));
617 }
618 let mut name = literal.finish(self.text, false)?;
619 if kind == token::IDENT {
621 name = truncate(name, &mut self.notices);
622 }
623 Ok(self.emit(kind, start, end, Value::Text(name)))
624 }
625
626 fn dollar(&mut self, start: usize) -> Result<Token<'a>, Error> {
628 let n = self.byte(start + 1);
629 if n.is_ascii_digit() {
630 let digits = self.bytes[start + 1..].iter().take_while(|b| b.is_ascii_digit()).count();
631 let end = start + 1 + digits;
632 if is_ident_start(self.byte(end)) {
633 let end = self.identifier_end(end);
634 return Err(self.syntax("trailing junk after parameter", start, end));
635 }
636 return match integer(&self.bytes[start + 1..end]) {
637 Some(n) => Ok(self.emit(token::PARAM, start, end, Value::Integer(n))),
638 None => Err(self.syntax("parameter number too large", start, end)),
639 };
640 }
641 match self.delimiter(start) {
642 Some(open) => self.dollar_quoted(start, open),
643 None => {
645 Ok(self.emit(character(b'$').unwrap_or(UNDEFINED), start, start + 1, Value::None))
646 }
647 }
648 }
649
650 fn delimiter(&self, i: usize) -> Option<usize> {
652 let mut j = i + 1;
653 if is_ident_start(self.byte(j)) {
654 j += self.bytes[j..].iter().take_while(|&&b| is_dolq_cont(b)).count();
655 }
656 (self.byte(j) == b'$').then_some(j + 1)
657 }
658
659 fn dollar_quoted(&mut self, start: usize, open: usize) -> Result<Token<'a>, Error> {
661 let bytes = self.bytes;
662 let tag = &bytes[start..open];
663 let mut i = open;
664 loop {
665 let Some(at) = bytes[i..].iter().position(|&b| b == b'$') else {
666 return Err(self.syntax("unterminated dollar-quoted string", start, bytes.len()));
667 };
668 let at = i + at;
669 match self.delimiter(at) {
670 Some(end) if &bytes[at..end] == tag => {
671 let value = Value::Text(Cow::Borrowed(&self.text[open..at]));
672 return Ok(self.emit(token::SCONST, start, end, value));
673 }
674 Some(end) => i = end - 1,
676 None => i = at + 1,
677 }
678 }
679 }
680
681 fn identifier_end(&self, i: usize) -> usize {
683 i + self.bytes[i..].iter().take_while(|&&b| is_ident_cont(b)).count()
684 }
685
686 fn identifier(&mut self, start: usize) -> Token<'a> {
688 let end = self.identifier_end(start + 1);
689 let word = &self.text[start..end];
690 if let Some(keyword) = keywords::lookup(word.as_bytes()) {
691 return self.emit(keyword.token, start, end, Value::Keyword(keyword));
692 }
693 let name = truncate(downcase(word), &mut self.notices);
694 self.emit(token::IDENT, start, end, Value::Text(name))
695 }
696
697 fn decimal(&self, i: usize) -> usize {
699 if !self.byte(i).is_ascii_digit() {
700 return 0;
701 }
702 let mut j = i + 1;
703 loop {
704 if self.byte(j).is_ascii_digit() {
705 j += 1;
706 } else if self.byte(j) == b'_' && self.byte(j + 1).is_ascii_digit() {
707 j += 2;
708 } else {
709 return j - i;
710 }
711 }
712 }
713
714 fn prefixed(&self, i: usize, radix: u32) -> usize {
716 let digit = |b: u8| char::from(b).is_digit(radix);
717 let mut j = i + 2;
718 loop {
719 if digit(self.byte(j)) {
720 j += 1;
721 } else if self.byte(j) == b'_' && digit(self.byte(j + 1)) {
722 j += 2;
723 } else {
724 return if j == i + 2 { 0 } else { j - i };
725 }
726 }
727 }
728
729 fn number(&mut self, start: usize) -> Result<Token<'a>, Error> {
731 #[derive(Clone, Copy)]
732 enum Rule {
733 Integer,
734 Prefixed,
735 HexFail,
736 OctFail,
737 BinFail,
738 Numeric,
739 NumericFail,
740 Real,
741 RealFail,
742 Junk,
743 }
744 let mut best = (0, Rule::Integer);
745 let mut offer = |length: usize, rule: Rule| {
746 if length > best.0 {
747 best = (length, rule);
748 }
749 };
750 let whole = self.decimal(start);
751 offer(whole, Rule::Integer);
752 if self.byte(start) == b'0' {
753 let (radix, fail) = match self.byte(start + 1) {
754 b'x' | b'X' => (16, Rule::HexFail),
755 b'o' | b'O' => (8, Rule::OctFail),
756 b'b' | b'B' => (2, Rule::BinFail),
757 _ => (0, Rule::Integer),
758 };
759 if radix != 0 {
760 offer(self.prefixed(start, radix), Rule::Prefixed);
761 offer(if self.byte(start + 2) == b'_' { 3 } else { 2 }, fail);
762 }
763 }
764 let numeric = if whole > 0 && self.byte(start + whole) == b'.' {
766 if self.byte(start + whole + 1) == b'.' {
767 offer(whole + 2, Rule::NumericFail);
768 }
769 whole + 1 + self.decimal(start + whole + 1)
770 } else if whole == 0 {
771 1 + self.decimal(start + 1)
772 } else {
773 0
774 };
775 offer(numeric, Rule::Numeric);
776 let mut real = 0;
777 for base in [whole, numeric] {
778 if base == 0 || !matches!(self.byte(start + base), b'e' | b'E') {
779 continue;
780 }
781 let mut j = start + base + 1;
782 let sign = matches!(self.byte(j), b'+' | b'-');
783 if sign {
784 j += 1;
785 }
786 let digits = self.decimal(j);
787 if digits > 0 {
788 real = real.max(j + digits - start);
789 offer(j + digits - start, Rule::Real);
790 } else if sign {
791 offer(j - start, Rule::RealFail);
792 }
793 }
794 for base in [whole, numeric, real] {
796 if base > 0 && is_ident_start(self.byte(start + base)) {
797 offer(self.identifier_end(start + base) - start, Rule::Junk);
798 }
799 }
800 let digits = start..start + whole.max(numeric).max(real);
801 for underscore in digits.filter(|&i| self.bytes[i] == b'_') {
802 offer(self.identifier_end(underscore) - start, Rule::Junk);
803 }
804 let (length, rule) = best;
805 let end = start + length;
806 let text = &self.text[start..end];
807 let message = match rule {
808 Rule::Integer | Rule::Prefixed | Rule::NumericFail => {
809 let end = if matches!(rule, Rule::NumericFail) { end - 2 } else { end };
810 let text = &self.text[start..end];
811 return Ok(match integer(text.as_bytes()) {
813 Some(n) => self.emit(token::ICONST, start, end, Value::Integer(n)),
814 None => self.emit(token::FCONST, start, end, Value::Text(Cow::Borrowed(text))),
815 });
816 }
817 Rule::Numeric | Rule::Real => {
818 return Ok(self.emit(token::FCONST, start, end, Value::Text(Cow::Borrowed(text))));
819 }
820 Rule::HexFail => "invalid hexadecimal integer",
821 Rule::OctFail => "invalid octal integer",
822 Rule::BinFail => "invalid binary integer",
823 Rule::RealFail | Rule::Junk => "trailing junk after numeric literal",
824 };
825 Err(self.syntax(message, start, end))
826 }
827
828 fn operator(&mut self, start: usize) -> Result<Token<'a>, Error> {
830 let run = &self.bytes
831 [start..start + self.bytes[start..].iter().take_while(|&&b| is_op_char(b)).count()];
832 let mut length = run.windows(2).position(|w| w == b"/*" || w == b"--").unwrap_or(run.len());
834 if length > 1 && matches!(run[length - 1], b'+' | b'-') {
836 let qualifying = |b: &u8| {
837 matches!(b, b'~' | b'!' | b'@' | b'#' | b'^' | b'&' | b'|' | b'`' | b'?' | b'%')
838 };
839 if !run[..length - 1].iter().any(qualifying) {
840 while length > 1 && matches!(run[length - 1], b'+' | b'-') {
841 length -= 1;
842 }
843 }
844 }
845 let end = start + length;
846 let kind = match &run[..length] {
847 [c] if is_self(*c) => character(*c),
848 b"=>" => Some(token::EQUALS_GREATER),
849 b"<=" => Some(token::LESS_EQUALS),
850 b">=" => Some(token::GREATER_EQUALS),
851 b"<>" | b"!=" => Some(token::NOT_EQUALS),
852 _ => None,
853 };
854 if let Some(kind) = kind {
855 return Ok(self.emit(kind, start, end, Value::None));
856 }
857 if length > NAME_LENGTH {
858 return Err(self.syntax("operator too long", start, end));
859 }
860 let value = Value::Text(Cow::Borrowed(&self.text[start..end]));
861 Ok(self.emit(token::OP, start, end, value))
862 }
863}
864
865#[cfg(test)]
866mod tests {
867 use super::*;
868 use crate::token::*;
869
870 fn lex(text: &str) -> Vec<(u16, Value<'_>)> {
872 let mut lexer = Lexer::new(text);
873 let mut tokens = Vec::new();
874 loop {
875 let token = lexer.next_token().unwrap();
876 if token.kind == 0 {
877 return tokens;
878 }
879 tokens.push((token.kind, token.value));
880 }
881 }
882
883 fn text(s: &str) -> Value<'_> {
884 Value::Text(Cow::Borrowed(s))
885 }
886
887 fn c(ch: u8) -> u16 {
888 character(ch).unwrap()
889 }
890
891 #[test]
892 fn names_and_keywords() {
893 let select = keywords::lookup(b"select").unwrap();
894 assert_eq!(
895 lex("SeLeCt Foo \"Foo\" é_$1"),
896 [
897 (SELECT, Value::Keyword(select)),
898 (IDENT, text("foo")),
899 (IDENT, text("Foo")),
900 (IDENT, text("é_$1")),
901 ]
902 );
903 assert_eq!(lex("U&x"), [(IDENT, text("u")), (OP, text("&")), (IDENT, text("x"))]);
905 assert_eq!(
906 lex("n'a'"),
907 [(NCHAR, Value::Keyword(keywords::lookup(b"nchar").unwrap())), (SCONST, text("a"))]
908 );
909 }
910
911 #[test]
912 fn long_names() {
913 let long = "a".repeat(70);
914 let mut lexer = Lexer::new(&long);
915 assert_eq!(lexer.next_token().unwrap().value, text(&long[..63]));
916 let notices = lexer.take_notices();
917 assert_eq!(notices.len(), 1);
918 assert_eq!(notices[0].code.as_str(), "42622");
919 let long = "é".repeat(40);
921 assert_eq!(lex(&long), [(IDENT, text(&long[..62]))]);
922 }
923
924 #[test]
925 fn strings() {
926 assert_eq!(lex("'it''s'"), [(SCONST, text("it's"))]);
927 assert_eq!(lex("'a\\b'"), [(SCONST, text("a\\b"))]);
928 assert_eq!(lex("'a'\n'b' 'c'"), [(SCONST, text("ab")), (SCONST, text("c"))]);
929 assert_eq!(lex("'a' -- x\n 'b'"), [(SCONST, text("ab"))]);
930 assert_eq!(lex("E'\\n\\t\\101\\x41\\'\\q'"), [(SCONST, text("\n\tAA'q"))]);
931 assert_eq!(lex("E'\\u00e9\\U0001F600\\ud83d\\ude00'"), [(SCONST, text("é😀😀"))]);
932 assert_eq!(lex("E'\\303\\251'"), [(SCONST, text("é"))]);
933 assert_eq!(lex("b'01' x'0F'"), [(BCONST, text("b01")), (XCONST, text("x0F"))]);
934 assert_eq!(lex("U&'\\0041'"), [(USCONST, text("\\0041"))]);
935 assert_eq!(lex("U&\"a\""), [(UIDENT, text("a"))]);
936 assert_eq!(lex("$$a'b$$ $x$a$y$b$x$"), [(SCONST, text("a'b")), (SCONST, text("a$y$b"))]);
937 assert_eq!(lex("$a")[0].0, UNDEFINED);
939 }
940
941 #[test]
942 fn numbers() {
943 assert_eq!(
944 lex("1 1_000 0x1F 0o17 0b101"),
945 [
946 (ICONST, Value::Integer(1)),
947 (ICONST, Value::Integer(1000)),
948 (ICONST, Value::Integer(31)),
949 (ICONST, Value::Integer(15)),
950 (ICONST, Value::Integer(5)),
951 ]
952 );
953 assert_eq!(
954 lex("2147483648 1.5 .5 1e3 1.5E-3"),
955 [
956 (FCONST, text("2147483648")),
957 (FCONST, text("1.5")),
958 (FCONST, text(".5")),
959 (FCONST, text("1e3")),
960 (FCONST, text("1.5E-3")),
961 ]
962 );
963 assert_eq!(
965 lex("1..2"),
966 [(ICONST, Value::Integer(1)), (DOT_DOT, Value::None), (ICONST, Value::Integer(2))]
967 );
968 assert_eq!(lex("$12"), [(PARAM, Value::Integer(12))]);
969 }
970
971 #[test]
972 fn operators() {
973 assert_eq!(
974 lex(":: := => <= >= <> != . ; :"),
975 [
976 (TYPECAST, Value::None),
977 (COLON_EQUALS, Value::None),
978 (EQUALS_GREATER, Value::None),
979 (LESS_EQUALS, Value::None),
980 (GREATER_EQUALS, Value::None),
981 (NOT_EQUALS, Value::None),
982 (NOT_EQUALS, Value::None),
983 (c(b'.'), Value::None),
984 (c(b';'), Value::None),
985 (c(b':'), Value::None),
986 ]
987 );
988 assert_eq!(lex("=-"), [(c(b'='), Value::None), (c(b'-'), Value::None)]);
990 assert_eq!(lex("@-"), [(OP, text("@-"))]);
991 assert_eq!(lex("<=-"), [(LESS_EQUALS, Value::None), (c(b'-'), Value::None)]);
992 assert_eq!(lex("+/*x*/-"), [(c(b'+'), Value::None), (c(b'-'), Value::None)]);
993 assert_eq!(lex("~--x"), [(OP, text("~"))]);
994 assert_eq!(lex("/* a /* b */ c */ 1")[0].0, ICONST);
995 }
996
997 #[test]
998 fn locations() {
999 let mut lexer = Lexer::new(" é 'x'\n");
1000 let token = lexer.next_token().unwrap();
1001 assert_eq!((token.start, token.end), (2, 4));
1002 let token = lexer.next_token().unwrap();
1003 assert_eq!((token.start, token.end), (5, 8));
1004 let token = lexer.next_token().unwrap();
1005 assert_eq!((token.kind, token.start, token.end), (0, 9, 9));
1006 assert_eq!(lex("1\u{0}2"), [(ICONST, Value::Integer(1))]);
1008 }
1009}