Files
wagslane 86874e2f9e turso
2024-03-07 09:48:38 -07:00

118 lines
3.5 KiB
Go

package sqliteparserutils
import (
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"github.com/libsql/sqlite-antlr4-parser/sqliteparser"
)
// TODO: Shell test begin transaction on shell
type SplitStatementExtraInfo struct {
IncompleteCreateTriggerStatement bool
IncompleteMultilineComment bool
LastTokenType int
}
func SplitStatement(statement string) (stmts []string, extraInfo SplitStatementExtraInfo) {
tokenStream := createTokenStream(statement)
stmtIntervals := make([]*antlr.Interval, 0)
currentIntervalStart := -1
insideCreateTriggerStmt := false
insideMultilineComment := false
var previousToken antlr.Token
var currentToken antlr.Token
for currentToken = tokenStream.LT(1); currentToken.GetTokenType() != antlr.TokenEOF; currentToken = tokenStream.LT(1) {
// We break loop here because we're sure multiline comment didn't finished, otherwise lexer would have just ignored
// it
if atIncompleteMultilineCommentStart(tokenStream) {
insideMultilineComment = true
break
}
if currentIntervalStart == -1 {
if currentToken.GetTokenType() == sqliteparser.SQLiteLexerSCOL {
previousToken = currentToken
tokenStream.Consume()
continue
}
currentIntervalStart = currentToken.GetTokenIndex()
if atCreateTriggerStart(tokenStream) {
insideCreateTriggerStmt = true
previousToken = currentToken
tokenStream.Consume()
continue
}
}
if insideCreateTriggerStmt {
if currentToken.GetTokenType() == sqliteparser.SQLiteLexerEND_ {
insideCreateTriggerStmt = false
}
} else if currentToken.GetTokenType() == sqliteparser.SQLiteLexerSCOL {
stmtIntervals = append(stmtIntervals, antlr.NewInterval(currentIntervalStart, previousToken.GetTokenIndex()))
currentIntervalStart = -1
}
previousToken = currentToken
tokenStream.Consume()
}
if currentIntervalStart != -1 && previousToken != nil {
stmtIntervals = append(stmtIntervals, antlr.NewInterval(currentIntervalStart, previousToken.GetTokenIndex()))
}
stmts = make([]string, 0)
for _, stmtInterval := range stmtIntervals {
stmts = append(stmts, tokenStream.GetTextFromInterval(stmtInterval))
}
lastTokenType := antlr.TokenInvalidType
if previousToken != nil {
lastTokenType = previousToken.GetTokenType()
}
return stmts, SplitStatementExtraInfo{IncompleteCreateTriggerStatement: insideCreateTriggerStmt, IncompleteMultilineComment: insideMultilineComment, LastTokenType: lastTokenType}
}
func atCreateTriggerStart(tokenStream antlr.TokenStream) bool {
if tokenStream.LT(1).GetTokenType() != sqliteparser.SQLiteLexerCREATE_ {
return false
}
if tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerTRIGGER_ {
return true
}
if tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerTEMP_ || tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerTEMPORARY_ &&
tokenStream.LT(3).GetTokenType() == sqliteparser.SQLiteLexerTRIGGER_ {
return true
}
return false
}
// Note: Only starts for incomplete multiline comments will be detected cause lexer automatically ignores complete
// multiline comments
func atIncompleteMultilineCommentStart(tokenStream antlr.TokenStream) bool {
if tokenStream.LT(1).GetTokenType() != sqliteparser.SQLiteLexerDIV {
return false
}
if tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerSTAR {
return true
}
return false
}
func createTokenStream(statement string) *antlr.CommonTokenStream {
statementStream := antlr.NewInputStream(statement)
lexer := sqliteparser.NewSQLiteLexer(statementStream)
return antlr.NewCommonTokenStream(lexer, 0)
}