2016-02-26 17:27:07 +00:00
|
|
|
|
// Copyright © 2016 Abcum Ltd
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
package sql
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"bytes"
|
|
|
|
|
"io"
|
2016-09-06 13:30:59 +00:00
|
|
|
|
"regexp"
|
2016-02-26 17:27:07 +00:00
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Scanner represents a lexical scanner.
|
|
|
|
|
type Scanner struct {
|
2016-09-07 15:40:05 +00:00
|
|
|
|
b []rune // any runes before
|
|
|
|
|
a []rune // any runes after
|
|
|
|
|
p *Parser
|
2016-02-26 17:27:07 +00:00
|
|
|
|
r *bufio.Reader
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewScanner returns a new instance of Scanner.
|
2016-09-07 15:40:05 +00:00
|
|
|
|
func NewScanner(p *Parser, r io.Reader) *Scanner {
|
|
|
|
|
return &Scanner{p: p, r: bufio.NewReader(r)}
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scan returns the next token and literal value.
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) Scan() (tok Token, lit string, val interface{}) {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
// Read the next rune.
|
2016-09-06 13:30:59 +00:00
|
|
|
|
ch := s.next()
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
// If we see whitespace then consume all contiguous whitespace.
|
2016-09-07 15:58:50 +00:00
|
|
|
|
if isBlank(ch) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanBlank(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:58:50 +00:00
|
|
|
|
// If we see a letter then consume as a string.
|
2016-02-26 17:27:07 +00:00
|
|
|
|
if isLetter(ch) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanIdent(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we see a number then consume as a number.
|
|
|
|
|
if isNumber(ch) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanNumber(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise read the individual character.
|
|
|
|
|
switch ch {
|
|
|
|
|
|
|
|
|
|
case eof:
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return EOF, "", val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '*':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ALL, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '×':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return MUL, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '∙':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return MUL, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '÷':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return DIV, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case ',':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return COMMA, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '.':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return DOT, string(ch), val
|
2016-09-07 15:58:05 +00:00
|
|
|
|
case '@':
|
|
|
|
|
return s.scanThing(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '"':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanString(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '\'':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanString(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '`':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanQuoted(ch)
|
2016-05-23 12:32:02 +00:00
|
|
|
|
case '⟨':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanQuoted(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '{':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanObject(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '[':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return s.scanObject(ch)
|
|
|
|
|
case '$':
|
|
|
|
|
return s.scanParams(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case ':':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return COLON, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case ';':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SEMICOLON, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case '(':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return LPAREN, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
case ')':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return RPAREN, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '¬':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return NEQ, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '≤':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return LTE, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '≥':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return GTE, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '~':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SIN, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '∋':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SIN, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '∌':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SNI, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '⊇':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return CONTAINSALL, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '⊃':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return CONTAINSSOME, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '⊅':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return CONTAINSNONE, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '∈':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return INS, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '∉':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return NIS, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '⊆':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ALLCONTAINEDIN, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '⊂':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SOMECONTAINEDIN, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '⊄':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return NONECONTAINEDIN, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '#':
|
|
|
|
|
return s.scanCommentSingle(ch)
|
2016-07-21 21:45:35 +00:00
|
|
|
|
case '/':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '*':
|
|
|
|
|
return s.scanCommentMultiple(ch)
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == ' ':
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return DIV, string(ch), val
|
2016-07-21 21:45:35 +00:00
|
|
|
|
default:
|
2016-09-06 13:30:59 +00:00
|
|
|
|
s.undo()
|
2016-07-21 21:45:35 +00:00
|
|
|
|
return s.scanRegexp(ch)
|
2016-07-04 10:37:37 +00:00
|
|
|
|
}
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '=':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '~':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SIN, "=~", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == '=':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return EEQ, "==", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return EQ, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '?':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '=':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ANY, "?=", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return QMARK, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '!':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '=':
|
|
|
|
|
if s.next() == '=' {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return NEE, "!==", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
} else {
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return NEQ, "!=", val
|
2016-07-04 10:37:37 +00:00
|
|
|
|
}
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == '~':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SNI, "!~", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return EXC, string(ch), val
|
2016-07-04 10:37:37 +00:00
|
|
|
|
}
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case '+':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '=':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return INC, "+=", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case isNumber(chn):
|
|
|
|
|
return s.scanNumber(ch, chn)
|
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ADD, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
case '-':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '=':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return DEC, "-=", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == '>':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return OEDGE, "->", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == '-':
|
|
|
|
|
return s.scanCommentSingle(ch)
|
|
|
|
|
case isNumber(chn):
|
|
|
|
|
return s.scanNumber(ch, chn)
|
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return SUB, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
case '>':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '=':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return GTE, ">=", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return GT, string(ch), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
case '<':
|
|
|
|
|
chn := s.next()
|
|
|
|
|
switch {
|
|
|
|
|
case chn == '>':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return NEQ, "<>", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == '=':
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return LTE, "<=", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
case chn == '-':
|
|
|
|
|
if s.next() == '>' {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return BEDGE, "<->", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
} else {
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return IEDGE, "<-", val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
s.undo()
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return LT, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ILLEGAL, string(ch), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// scanBlank consumes the current rune and all contiguous whitespace.
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanBlank(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
tok = WS
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Create a buffer
|
2016-02-26 17:27:07 +00:00
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
2016-02-26 17:27:07 +00:00
|
|
|
|
for {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
if ch := s.next(); ch == eof {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
break
|
2016-09-07 15:58:50 +00:00
|
|
|
|
} else if !isBlank(ch) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
s.undo()
|
2016-02-26 17:27:07 +00:00
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// scanCommentSingle consumes the current rune and all contiguous whitespace.
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanCommentSingle(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
tok = WS
|
|
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
|
|
|
|
for {
|
|
|
|
|
if ch := s.next(); ch == '\n' || ch == '\r' {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// scanCommentMultiple consumes the current rune and all contiguous whitespace.
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanCommentMultiple(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
tok = WS
|
|
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
|
|
|
|
for {
|
|
|
|
|
if ch := s.next(); ch == eof {
|
|
|
|
|
break
|
|
|
|
|
} else if ch == '*' {
|
|
|
|
|
if chn := s.next(); chn == '/' {
|
|
|
|
|
buf.WriteRune(chn)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanParams(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
tok, lit, val = s.scanIdent(chp...)
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
2016-09-07 15:40:05 +00:00
|
|
|
|
if s.p.is(tok, IDENT) {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return PARAM, lit, nil
|
2016-09-06 13:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// scanIdent consumes the current rune and all contiguous ident runes.
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanIdent(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
tok = IDENT
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Create a buffer
|
2016-02-26 17:27:07 +00:00
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
2016-02-26 17:27:07 +00:00
|
|
|
|
for {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
if ch := s.next(); ch == eof {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
break
|
|
|
|
|
} else if !isIdentChar(ch) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
s.undo()
|
2016-02-26 17:27:07 +00:00
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the string matches a keyword then return that keyword.
|
|
|
|
|
if tok := keywords[strings.ToUpper(buf.String())]; tok > 0 {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
if val, err := time.ParseDuration(buf.String()); err == nil {
|
|
|
|
|
return DURATION, buf.String(), val
|
2016-05-23 12:32:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-26 17:27:07 +00:00
|
|
|
|
// Otherwise return as a regular identifier.
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:58:05 +00:00
|
|
|
|
// scanThing consumes the current rune and all contiguous ident runes.
|
|
|
|
|
func (s *Scanner) scanThing(chp ...rune) (tok Token, lit string, val interface{}) {
|
|
|
|
|
|
|
|
|
|
tok = THING
|
|
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
var beg bytes.Buffer
|
|
|
|
|
var mid bytes.Buffer
|
|
|
|
|
var end bytes.Buffer
|
|
|
|
|
|
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
if ch := s.next(); ch == eof {
|
|
|
|
|
break
|
|
|
|
|
} else if isLetter(ch) {
|
|
|
|
|
tok, lit, _ = s.scanIdent(ch)
|
|
|
|
|
beg.WriteString(lit)
|
|
|
|
|
} else if isNumber(ch) {
|
|
|
|
|
tok, lit, _ = s.scanNumber(ch)
|
|
|
|
|
beg.WriteString(lit)
|
|
|
|
|
} else if ch == '`' {
|
|
|
|
|
tok, lit, _ = s.scanQuoted(ch)
|
|
|
|
|
beg.WriteString(lit)
|
|
|
|
|
} else if ch == '{' {
|
|
|
|
|
tok, lit, _ = s.scanQuoted(ch)
|
|
|
|
|
beg.WriteString(lit)
|
|
|
|
|
} else if ch == '⟨' {
|
|
|
|
|
tok, lit, _ = s.scanQuoted(ch)
|
|
|
|
|
beg.WriteString(lit)
|
|
|
|
|
} else {
|
|
|
|
|
s.undo()
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if beg.Len() < 1 {
|
|
|
|
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
if ch := s.next(); ch != ':' {
|
|
|
|
|
s.undo()
|
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
mid.WriteRune(ch)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if mid.Len() < 1 {
|
|
|
|
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
if ch := s.next(); ch == eof {
|
|
|
|
|
break
|
|
|
|
|
} else if isLetter(ch) {
|
|
|
|
|
tok, lit, _ = s.scanIdent(ch)
|
|
|
|
|
end.WriteString(lit)
|
|
|
|
|
} else if isNumber(ch) {
|
|
|
|
|
tok, lit, _ = s.scanNumber(ch)
|
|
|
|
|
end.WriteString(lit)
|
|
|
|
|
} else if ch == '`' {
|
|
|
|
|
tok, lit, _ = s.scanQuoted(ch)
|
|
|
|
|
beg.WriteString(lit)
|
|
|
|
|
} else if ch == '{' {
|
|
|
|
|
tok, lit, _ = s.scanQuoted(ch)
|
|
|
|
|
end.WriteString(lit)
|
|
|
|
|
} else if ch == '⟨' {
|
|
|
|
|
tok, lit, _ = s.scanQuoted(ch)
|
|
|
|
|
end.WriteString(lit)
|
|
|
|
|
} else {
|
|
|
|
|
s.undo()
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if end.Len() < 1 {
|
|
|
|
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = &Thing{
|
|
|
|
|
TB: beg.String(),
|
|
|
|
|
ID: end.String(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch tok {
|
|
|
|
|
case DATE, TIME, NUMBER, DOUBLE:
|
|
|
|
|
val.(*Thing).ID, _ = s.p.declare(tok, end.String())
|
|
|
|
|
case REGION:
|
|
|
|
|
return ILLEGAL, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise return as a regular thing.
|
|
|
|
|
return THING, buf.String() + beg.String() + mid.String() + end.String(), val
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanNumber(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-05-23 12:32:02 +00:00
|
|
|
|
|
|
|
|
|
tok = NUMBER
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Create a buffer
|
2016-05-23 12:32:02 +00:00
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
2016-05-23 12:32:02 +00:00
|
|
|
|
for {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
if ch := s.next(); ch == eof {
|
2016-05-23 12:32:02 +00:00
|
|
|
|
break
|
|
|
|
|
} else if isNumber(ch) {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
} else if isLetter(ch) {
|
|
|
|
|
tok = IDENT
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
} else if ch == '.' {
|
|
|
|
|
if tok == DOUBLE {
|
|
|
|
|
tok = IDENT
|
|
|
|
|
}
|
|
|
|
|
if tok == NUMBER {
|
|
|
|
|
tok = DOUBLE
|
|
|
|
|
}
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
} else {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
s.undo()
|
2016-05-23 12:32:02 +00:00
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), nil
|
2016-05-23 12:32:02 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanQuoted(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
tok, lit, val = s.scanString(chp...)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
2016-09-07 15:40:05 +00:00
|
|
|
|
if s.p.is(tok, STRING) {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return IDENT, lit, nil
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanString(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
beg := chp[0]
|
2016-05-23 12:32:02 +00:00
|
|
|
|
end := beg
|
|
|
|
|
|
|
|
|
|
if beg == '"' {
|
|
|
|
|
end = '"'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if beg == '`' {
|
|
|
|
|
end = '`'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if beg == '⟨' {
|
|
|
|
|
end = '⟩'
|
|
|
|
|
}
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
2016-09-07 15:58:05 +00:00
|
|
|
|
if beg == '{' {
|
|
|
|
|
end = '}'
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
tok = STRING
|
|
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
|
|
// Ignore passed in runes
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
2016-02-26 17:27:07 +00:00
|
|
|
|
for {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
if ch := s.next(); ch == end {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
break
|
|
|
|
|
} else if ch == eof {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ILLEGAL, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
} else if ch == '\n' {
|
|
|
|
|
tok = REGION
|
|
|
|
|
buf.WriteRune(ch)
|
2016-05-23 12:32:02 +00:00
|
|
|
|
} else if ch == '\r' {
|
|
|
|
|
tok = REGION
|
|
|
|
|
buf.WriteRune(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
} else if ch == '\\' {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
switch chn := s.next(); chn {
|
2016-05-23 12:32:02 +00:00
|
|
|
|
default:
|
|
|
|
|
buf.WriteRune(chn)
|
|
|
|
|
case 'b':
|
|
|
|
|
continue
|
|
|
|
|
case 't':
|
2016-09-06 13:30:59 +00:00
|
|
|
|
tok = REGION
|
2016-05-23 12:32:02 +00:00
|
|
|
|
buf.WriteRune('\t')
|
|
|
|
|
case 'r':
|
|
|
|
|
tok = REGION
|
|
|
|
|
buf.WriteRune('\r')
|
|
|
|
|
case 'n':
|
|
|
|
|
tok = REGION
|
2016-02-26 17:27:07 +00:00
|
|
|
|
buf.WriteRune('\n')
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
if val, err := time.ParseDuration(buf.String()); err == nil {
|
|
|
|
|
return DURATION, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-14 20:57:42 +00:00
|
|
|
|
if val, err := time.Parse(RFCDate, buf.String()); err == nil {
|
|
|
|
|
return DATE, buf.String(), val.UTC()
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-14 20:57:42 +00:00
|
|
|
|
if val, err := time.Parse(RFCTime, buf.String()); err == nil {
|
|
|
|
|
return TIME, buf.String(), val.UTC()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if val, err := time.Parse(RFCNorm, buf.String()); err == nil {
|
|
|
|
|
return TIME, buf.String(), val.UTC()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if val, err := time.Parse(RFCText, buf.String()); err == nil {
|
|
|
|
|
return TIME, buf.String(), val.UTC()
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanRegexp(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
tok = IDENT
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Create a buffer
|
2016-02-26 17:27:07 +00:00
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// Ignore passed in runes
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
|
|
|
|
for {
|
|
|
|
|
if ch := s.next(); ch == chp[0] {
|
|
|
|
|
break
|
|
|
|
|
} else if ch == eof {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ILLEGAL, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
} else if ch == '\\' {
|
|
|
|
|
chn := s.next()
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
buf.WriteRune(chn)
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
if val, err := regexp.Compile(buf.String()); err == nil {
|
|
|
|
|
return REGEX, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return tok, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
func (s *Scanner) scanObject(chp ...rune) (tok Token, lit string, val interface{}) {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
|
|
|
|
beg := chp[0]
|
2016-02-26 17:27:07 +00:00
|
|
|
|
end := beg
|
2016-05-23 12:32:02 +00:00
|
|
|
|
sub := 0
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
if beg == '{' {
|
|
|
|
|
end = '}'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if beg == '[' {
|
|
|
|
|
end = ']'
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
tok = IDENT
|
|
|
|
|
|
|
|
|
|
// Create a buffer
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
|
|
// Read passed in runes
|
|
|
|
|
for _, ch := range chp {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read subsequent characters
|
2016-02-26 17:27:07 +00:00
|
|
|
|
for {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
if ch := s.next(); ch == end && sub == 0 {
|
|
|
|
|
buf.WriteRune(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
break
|
2016-05-23 12:32:02 +00:00
|
|
|
|
} else if ch == beg {
|
|
|
|
|
sub++
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
} else if ch == end {
|
|
|
|
|
sub--
|
|
|
|
|
buf.WriteRune(ch)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
} else if ch == eof {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ILLEGAL, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
} else if ch == '\\' {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
switch chn := s.next(); chn {
|
2016-05-23 12:32:02 +00:00
|
|
|
|
default:
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ILLEGAL, buf.String(), val
|
2016-05-23 12:32:02 +00:00
|
|
|
|
case 'b', 't', 'r', 'n', 'f', '"', '\\':
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
buf.WriteRune(chn)
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-23 12:32:02 +00:00
|
|
|
|
if beg == '{' {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return JSON, buf.String(), val
|
2016-09-06 13:30:59 +00:00
|
|
|
|
}
|
|
|
|
|
if beg == '[' {
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ARRAY, buf.String(), val
|
2016-05-23 12:32:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:53:04 +00:00
|
|
|
|
return ILLEGAL, buf.String(), val
|
2016-02-26 17:27:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// next reads the next rune from the bufferred reader.
|
2016-02-26 17:27:07 +00:00
|
|
|
|
// Returns the rune(0) if an error occurs (or io.EOF is returned).
|
2016-09-06 13:30:59 +00:00
|
|
|
|
func (s *Scanner) next() rune {
|
|
|
|
|
|
2016-09-07 15:40:05 +00:00
|
|
|
|
if len(s.a) > 0 {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
var r rune
|
2016-09-07 15:40:05 +00:00
|
|
|
|
r, s.a = s.a[len(s.a)-1], s.a[:len(s.a)-1]
|
|
|
|
|
s.b = append(s.b, r)
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r, _, err := s.r.ReadRune()
|
2016-02-26 17:27:07 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return eof
|
|
|
|
|
}
|
2016-09-07 15:40:05 +00:00
|
|
|
|
s.b = append(s.b, r)
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return r
|
|
|
|
|
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// undo places the previously read rune back on the reader.
|
|
|
|
|
func (s *Scanner) undo() {
|
|
|
|
|
|
2016-09-07 15:40:05 +00:00
|
|
|
|
if len(s.b) > 0 {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
var r rune
|
2016-09-07 15:40:05 +00:00
|
|
|
|
r, s.b = s.b[len(s.b)-1], s.b[:len(s.b)-1]
|
|
|
|
|
s.a = append(s.a, r)
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-26 17:27:07 +00:00
|
|
|
|
_ = s.r.UnreadRune()
|
2016-09-06 13:30:59 +00:00
|
|
|
|
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-07 15:58:50 +00:00
|
|
|
|
// isBlank returns true if the rune is a space, tab, or newline.
|
|
|
|
|
func isBlank(ch rune) bool {
|
2016-05-23 12:32:02 +00:00
|
|
|
|
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isNumber returns true if the rune is a number.
|
|
|
|
|
func isNumber(ch rune) bool {
|
|
|
|
|
return (ch >= '0' && ch <= '9')
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// isLetter returns true if the rune is a letter.
|
|
|
|
|
func isLetter(ch rune) bool {
|
|
|
|
|
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-06 13:30:59 +00:00
|
|
|
|
// isIdentChar returns true if the rune is allowed in a IDENT.
|
2016-02-26 17:27:07 +00:00
|
|
|
|
func isIdentChar(ch rune) bool {
|
2016-09-06 13:30:59 +00:00
|
|
|
|
return isLetter(ch) || isNumber(ch) || ch == '.' || ch == '_' || ch == '*'
|
2016-02-26 17:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// eof represents a marker rune for the end of the reader.
|
|
|
|
|
var eof = rune(0)
|