MMQLEngine/mmql/engine/lexer.go

380 lines
8.9 KiB
Go

package engine
import (
"fmt"
"io"
"strings"
"strconv"
stmtd "github.com/tgckpg/mmqlengine/mmql/statements"
)
type LexerExpect struct {
Statements bool
Keywords bool
Brackets bool
Quotes bool
Key string
}
type Lexer struct {
SupportedStmts *map[string] func( *Lexer ) ( stmtd.IStatement, error )
reader *strings.Reader
readToken bool
}
func ( this *Lexer ) Parse( line string ) ( stmtd.IStatement, error ) {
this.reader = strings.NewReader( line )
ex := LexerExpect{
Statements: true,
Keywords: false,
Brackets: true,
Quotes: true,
}
return this.ReadStatement( &ex )
}
func ( this *Lexer ) SetReader( reader *strings.Reader ) {
this.reader = reader
}
func ( this *Lexer ) GetPos() int {
return this.reader.Len()
}
/**
* Reads
* 123,456,789.00001
* 1234.567
* 1234
* 10.5k
*/
func ( this *Lexer ) ReadDecimal() ( f float64, err error ) {
reader := this.reader
defer this.Rollback( reader.Len(), &err )
var b strings.Builder
dot := false
comma := false
k := false
end := false
for {
r, _, _err := reader.ReadRune()
err = _err
if err != nil {
if err == io.EOF {
if comma {
err = fmt.Errorf( "Unexpected ',' char" )
return
}
if b.Len() == 0 {
err = fmt.Errorf( "Nothing left to read" )
return
}
}
break
}
if end && !strings.ContainsRune( K_SPACES, r ) {
if k {
b.WriteRune( 'k' )
}
err = fmt.Errorf(
"Cannot parse '%s' in ReadDecimal",
this.ReadUntilNot( K_STATEMENT_CHARS, true, r ),
)
return
}
if r == ',' {
if comma || dot {
err = fmt.Errorf( "Unexpected ',' char in ReadDecimal" )
return
}
comma = true
continue
}
if strings.ContainsRune( K_SPACES, r ) {
if comma {
err = fmt.Errorf( "Unexpected ',' char in ReadDecimal" )
return
}
if 0 < b.Len() {
break
}
continue
}
if r == '.' {
if !dot {
b.WriteRune( r )
dot = true
continue
}
err = fmt.Errorf( "Unexpected '.' char in ReadDecimal" )
return
}
if r == 'k' {
k = true
end = true
continue
}
if '0' <= r && r <= '9' {
b.WriteRune( r )
comma = false
} else {
err = fmt.Errorf(
"Cannot parse '%s' in ReadDecimal",
this.ReadUntilNot( K_STATEMENT_CHARS, true, r ),
)
return
}
}
f, err = strconv.ParseFloat( b.String(), 64 )
if k {
f *= 1000
}
return
}
func ( this *Lexer ) Rollback( oPos int, err *error ) {
if *err != nil {
this.reader.Seek( int64( this.reader.Len() - oPos ), io.SeekCurrent )
}
}
func ( this *Lexer ) ReadKeyword( Keyword string ) ( err error ) {
reader := this.reader
kReader := strings.NewReader( Keyword )
defer this.Rollback( reader.Len(), &err )
var b strings.Builder
for {
r, _, _err := reader.ReadRune()
err = _err
if err != nil {
if err == io.EOF {
if 0 < b.Len() {
err = nil
} else {
err = fmt.Errorf( "Nothing left to read" )
return
}
}
break
}
if strings.ContainsRune( K_SPACES, r ) && b.Len() == 0 {
continue
}
k, _, _err := kReader.ReadRune()
if _err != nil {
if _err != io.EOF {
err = _err
} else {
err = nil
}
return
}
if k != r {
err = fmt.Errorf(
"Expected \"%s\", got \"%s\"",
Keyword,
this.ReadUntilNot( K_STATEMENT_CHARS, true, r ),
)
return
}
b.WriteRune( r )
}
return
}
func ( this *Lexer ) ReadAlpha() ( s string, err error ) {
reader := this.reader
defer this.Rollback( reader.Len(), &err )
var b strings.Builder
for {
r, _, _err := reader.ReadRune()
err = _err
if err != nil {
if err == io.EOF {
if 0 < b.Len() {
err = nil
} else {
err = fmt.Errorf( "Nothing left to read" )
return
}
}
break
}
if strings.ContainsRune( K_SPACES, r ) {
if 0 < b.Len() {
break
}
continue
}
if ( 'A' <= r && r <= 'Z' ) || ( 'a' <= r && r <= 'z' ) {
b.WriteRune( r )
}
}
s = b.String()
return
}
func ( this *Lexer ) ReadStatement( expecting *LexerExpect ) ( stmtd.IStatement, error ) {
reader := this.reader
var stmt stmtd.IStatement
for {
r, _, err := reader.ReadRune()
if err != nil {
return nil, err
}
if expecting.Quotes && strings.ContainsRune( K_QUOTES, r ) {
s, err := this.ReadUntilClose( r, true, '\\' )
if err != nil {
return nil, err
}
stmt = stmtd.QuotedValue{
RawStatement: &stmtd.RawStatement{ Value: s },
Quote: string( r ),
}
return stmt, nil
}
bracketIndex := strings.IndexRune( K_BRACKETS, r )
if expecting.Brackets && bracketIndex % 2 == 0 {
cl := rune( K_BRACKETS[ bracketIndex + 1 ] )
s, err := this.ReadUntilClose( cl, false, 'A' )
if err != nil {
return nil, err
}
var b strings.Builder
b.WriteRune( r )
b.WriteRune( cl )
stmt = stmtd.BracketedValue{
RawStatement: &stmtd.RawStatement{ Value: s },
Brackets: b.String(),
}
return stmt, nil
}
s := expecting.Key
if s == "" && strings.ContainsRune( K_STATEMENT_CHARS, r ) {
s = this.ReadUntilNot( K_STATEMENT_CHARS, true, r )
}
if expecting.Statements && s != "" {
if this.SupportedStmts == nil {
return nil, fmt.Errorf( "Statement not supported: %s", s )
}
if f, ok := (*this.SupportedStmts)[ strings.ToUpper( s ) ]; ok {
// If we are using key, we need to move 1 rune back
if expecting.Key != "" {
err = reader.UnreadRune()
if err != nil {
return nil, err
}
}
return f( this )
} else {
var supported strings.Builder
comma := false
for k := range *this.SupportedStmts {
if comma {
supported.WriteString( ", " )
} else {
comma = true
}
supported.WriteString( k )
}
return nil, fmt.Errorf( "Statement not supported: %s, supported statements are: %s", s, supported.String() )
}
}
}
return nil, fmt.Errorf( "Nothing to read" )
}
func ( this *Lexer ) ReadUntilNot( charRange string, writeHead bool, head rune ) string {
var b strings.Builder
if writeHead {
b.WriteRune( head )
}
reader := this.reader
for {
r, _, err := reader.ReadRune()
if err == nil && strings.ContainsRune( charRange, r ) {
b.WriteRune( r )
} else {
break
}
}
return b.String()
}
func ( this *Lexer ) ReadUntilClose( closing rune, canEsc bool, escRune rune ) ( string, error ) {
var b strings.Builder
reader := this.reader
for {
r, _, err := reader.ReadRune()
if err != nil {
if err == io.EOF {
return "", fmt.Errorf( "Unexpected end of data after opening %s", string( closing ) )
}
return "", err
}
if r == closing {
break
} else if canEsc && r == escRune {
r2, _, err := reader.ReadRune()
if err != nil {
return "", err
}
if r2 != closing {
b.WriteRune( r )
b.WriteRune( r2 )
continue
}
}
b.WriteRune( r )
}
return b.String(), nil
}