From 925c1d70c0d1e34d8446064ebc7635bb8715c34e Mon Sep 17 00:00:00 2001 From: takayahilton Date: Mon, 5 Oct 2020 18:27:55 +0900 Subject: [PATCH] Some optimizations --- .gitignore | 1 + .../sqlformatter/core/Formatter.scala | 17 +++----- .../sqlformatter/core/Indentation.scala | 3 +- .../sqlformatter/core/InlineBlock.scala | 36 +++++++++-------- .../sqlformatter/core/Token.scala | 8 +--- .../sqlformatter/core/Tokenizer.scala | 11 +++--- .../sqlformatter/core/util/package.scala | 39 +++++++++---------- 7 files changed, 52 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index f45b327..ad9c917 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ .idea/ +.bsp lowered.hnir diff --git a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Formatter.scala b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Formatter.scala index 47f48c3..9ec7cd8 100644 --- a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Formatter.scala +++ b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Formatter.scala @@ -154,19 +154,12 @@ class Formatter(cfg: FormatConfig, tokenizer: Tokenizer) { util.trimEnd(query) } - private def previousNonWhitespaceToken = { - var n = 1 - while (previousToken(n).exists(_.tokenType == TokenTypes.WHITESPACE)) { - n += 1 - } - previousToken(n) - } + private def previousNonWhitespaceToken = + tokens.take(index).reverseIterator.find(_.tokenType != TokenTypes.WHITESPACE) - private def previousToken(offset: Int): Option[Token] = - if (index - offset < 0) + private def previousToken: Option[Token] = + if (index - 1 < 0) None else - Some(tokens(index - offset)) - - private def previousToken: Option[Token] = previousToken(1) + Some(tokens(index - 1)) } diff --git a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Indentation.scala b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Indentation.scala index 1e0fb18..0c1d9f7 100644 --- a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Indentation.scala +++ b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Indentation.scala @@ -48,8 +48,7 @@ private[core] class Indentation(indent: String) { * throws away these as well. */ def decreaseBlockLevel(): Unit = { - indentTypes = indentTypes.dropWhile(_ == IndentTypes.INDENT_TYPE_TOP_LEVEL) - indentTypes = indentTypes.drop(1) + indentTypes = indentTypes.dropWhile(_ == IndentTypes.INDENT_TYPE_TOP_LEVEL).drop(1) } } diff --git a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/InlineBlock.scala b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/InlineBlock.scala index d3f1d74..0ace77d 100644 --- a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/InlineBlock.scala +++ b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/InlineBlock.scala @@ -1,5 +1,7 @@ package com.github.takayahilton.sqlformatter.core +import scala.annotation.tailrec + /** * Bookkeeper for inline blocks. *

@@ -8,6 +10,8 @@ package com.github.takayahilton.sqlformatter.core * expressions where open-parenthesis causes newline and increase of indentation. */ private[core] class InlineBlock { + import InlineBlock._ + private[this] var level: Int = 0 /** @@ -37,25 +41,27 @@ private[core] class InlineBlock { * @return {Boolean} */ def isActive: Boolean = level > 0 +} + +private[core] object InlineBlock { + private val INLINE_MAX_LENGTH: Int = 50 // Check if this should be an inline parentheses block // Examples are "NOW()", "COUNT(*)", "int(10)", key(`somecolumn`), DECIMAL(7,2) private def isInlineBlock(tokens: Vector[Token], index: Int): Boolean = { - var length = 0 - var level = 0 - for (i <- index until tokens.size) { - val token = tokens(i) - length += token.value.length + @tailrec + def go(tokens: List[Token], length: Int, level: Int): Boolean = tokens match { // Overran max length - if (length > InlineBlock.INLINE_MAX_LENGTH) return false - if (token.tokenType == TokenTypes.OPEN_PAREN) level += 1 - else if (token.tokenType == TokenTypes.CLOSE_PAREN) { - level -= 1 - if (level == 0) return true - } - if (isForbiddenToken(token)) return false + case _ if length > InlineBlock.INLINE_MAX_LENGTH => false + case Nil => false + case token :: tail if token.tokenType == TokenTypes.OPEN_PAREN => + go(tail, length + token.value.length, level + 1) + case token :: tail if token.tokenType == TokenTypes.CLOSE_PAREN => + level < 2 || go(tail, length + token.value.length, level - 1) + case token :: _ if isForbiddenToken(token) => false + case token :: tail => go(tail, length + token.value.length, level) } - false + go(tokens.drop(index).toList, 0, 0) } // Reserved words that cause newlines, comments and semicolons @@ -66,7 +72,3 @@ private[core] class InlineBlock { token.value == ";" } } - -private[core] object InlineBlock { - private val INLINE_MAX_LENGTH: Int = 50 -} diff --git a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Token.scala b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Token.scala index d6fb696..7aca88e 100644 --- a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Token.scala +++ b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Token.scala @@ -3,20 +3,16 @@ package com.github.takayahilton.sqlformatter.core final case class Token( tokenType: TokenTypes, value: String, - regex: Option[String], key: Option[String] ) { def withKey(key: String): Token = copy(key = Some(key)) override def toString: String = - s"(type: $tokenType, value [$value]" + regex.fold(")")(r => s"regex: /$r/)") + s"(type: $tokenType, value [$value]" + ")" } object Token { - def apply(tokenType: TokenTypes, value: String, regex: String): Token = - new Token(tokenType, value, Some(regex), None) - def apply(tokenType: TokenTypes, value: String): Token = - new Token(tokenType, value, None, None) + new Token(tokenType, value, None) } diff --git a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Tokenizer.scala b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Tokenizer.scala index 02f3e3e..0101de8 100644 --- a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Tokenizer.scala +++ b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/Tokenizer.scala @@ -96,12 +96,11 @@ class Tokenizer(val cfg: DialectConfig) { @scala.annotation.tailrec def go(input: String, previousToken: Option[Token], tokens: VectorBuilder[Token]): Vector[Token] = - input match { - case "" => - tokens.result() - case _ => - val token = getNextToken(input, previousToken).get // if token is None, something is wrong - go(input.substring(token.value.length), Some(token), tokens += token) + if (input.isEmpty) + tokens.result() + else { + val token = getNextToken(input, previousToken).get // if token is None, something is wrong + go(input.substring(token.value.length), Some(token), tokens += token) } go(input, None, new VectorBuilder) diff --git a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/util/package.scala b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/util/package.scala index d0f5fb8..d33b290 100644 --- a/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/util/package.scala +++ b/shared/src/main/scala/com/github/takayahilton/sqlformatter/core/util/package.scala @@ -5,26 +5,25 @@ import java.util.regex.Pattern package object util { def trimEnd(s: String): String = s.replaceAll("[ |\\n|\\r]*$", "") - def escapeRegExp(s: String): String = { - val regexp = List( - "^", - "$", - "\\", - ".", - "*", - "+", - "*", - "?", - "(", - ")", - "[", - "]", - "{", - "}", - "|" - ).map(spChr => "(\\" + spChr + ")") - .mkString("|") + private[this] val regexp = List( + "^", + "$", + "\\", + ".", + "*", + "+", + "*", + "?", + "(", + ")", + "[", + "]", + "{", + "}", + "|" + ).map(spChr => "(\\" + spChr + ")") + .mkString("|") + def escapeRegExp(s: String): String = Pattern.compile(regexp).matcher(s).replaceAll("\\\\$0") - } }