func()

in sqlutil/scanner.go [62:172]


func (s *Scanner) scan() Token {
	r, ok := s.next()
	if !ok {
		return eof
	}
	for unicode.IsSpace(r) {
		if r, ok = s.next(); !ok {
			return eof
		}
	}
	s.start = s.pos - utf8.RuneLen(r)

	if r == '_' || unicode.IsLetter(r) {
		return s.scanKeywordOrIdentifier(r != '_')
	} else if unicode.IsDigit(r) {
		return s.scanNumericLiteral()
	}

	switch r {
	case '\'':
		// Standard string literal.
		return s.scanStringLiteral()
	case '"':
		// Standard double-quoted identifier.
		//
		// NOTE(axw) MySQL will treat " as a
		// string literal delimiter by default,
		// but we assume standard SQL and treat
		// it as a identifier delimiter.
		return s.scanQuotedIdentifier('"')
	case '[':
		// T-SQL bracket-quoted identifier.
		return s.scanQuotedIdentifier(']')
	case '`':
		// MySQL-style backtick-quoted identifier.
		return s.scanQuotedIdentifier('`')
	case '(':
		return LPAREN
	case ')':
		return RPAREN
	case '-':
		if next, ok := s.peek(); ok && next == '-' {
			// -- comment
			s.next()
			return s.scanSimpleComment()
		}
		return OTHER
	case '/':
		if next, ok := s.peek(); ok {
			switch next {
			case '*':
				// /* comment */
				s.next()
				return s.scanBracketedComment()
			case '/':
				// // comment
				s.next()
				return s.scanSimpleComment()
			}
		}
		return OTHER
	case '.':
		return PERIOD
	case '$':
		next, ok := s.peek()
		if !ok {
			break
		}
		if unicode.IsDigit(next) {
			// This is a variable like "$1".
			for {
				if next, ok := s.peek(); !ok || !unicode.IsDigit(next) {
					break
				}
				s.next()
			}
			return OTHER
		} else if next == '$' || next == '_' || unicode.IsLetter(next) {
			// PostgreSQL supports dollar-quoted string literal syntax,
			// like $foo$...$foo$. The tag (foo in this case) is optional,
			// and if present follows identifier rules.
			for {
				r, ok := s.next()
				if !ok {
					// Unknown token starting with $ until
					// EOF, just ignore it.
					return OTHER
				}
				switch {
				case r == '$':
					// This marks the end of the initial $foo$.
					tag := s.Text()
					if i := strings.Index(s.input[s.pos:], tag); i >= 0 {
						s.end += i + len(tag)
						s.pos += i + len(tag)
						return STRING
					}
				case unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_':
					// Identifier rune, consume.
				case unicode.IsSpace(r):
					// Unknown token starting with $,
					// consume runes until space.
					s.end -= utf8.RuneLen(r)
					return OTHER
				}
			}
		}
		return OTHER
	}
	return OTHER
}