package codeformat
class PythonFormat <: BaseLanguage {
let arrayListFlagTry: ArrayList<FlagBean> = ArrayList<FlagBean>()
let arrayListFlagIf: ArrayList<FlagBean> = ArrayList<FlagBean>()
func doTryFlag(lineBean: LineBean) {
if (lineBean.codeLine.trimAscii().startsWith("try:")) {
let flagBean = FlagBean("try", lineBean.indentLevel)
arrayListFlagTry.add(flagBean)
}
}
func doIfFlag(lineBean: LineBean) {
if (lineBean.codeLine.trimAscii().startsWith("if ")) {
let flagBean = FlagBean("if", lineBean.indentLevel)
arrayListFlagIf.add(flagBean)
}
}
public override func dealWithNewLine(stateBean: StateBean): Unit {
if (stateBean.perLineOutput.size > 0) {
let lineBean: LineBean = LineBean()
lineBean.codeLine = stateBean.perLineOutput.toString()
setLineFlagsAndIndent(lineBean, stateBean)
setCommonFields(lineBean, stateBean)
doTryFlag(lineBean)
doIfFlag(lineBean)
stateBean.linesList.add(lineBean)
if (stateBean.isInRetuen) {
stateBean.indentLevel--
stateBean.isInRetuen = false
} else {
if (lineBean.codeLine.trimAscii().size != 0) {
stateBean.isLastLineReturn = false
}
}
if (stateBean.isInContinue) {
stateBean.indentLevel--
stateBean.isInContinue = false
}
if (stateBean.isInBreak) {
stateBean.indentLevel--
stateBean.isInBreak = false
}
stateBean.perLineOutput = StringBuilder()
stateBean.perLineStartIndex = stateBean.currentIndex + 1
stateBean.lastChar = r'\n'
}
}
public func dealWithColon(stateBean: StateBean): Unit {
let lb = createLineBean(stateBean, 0)
setLineFlagsAndIndent(lb, stateBean)
setCommonFields(lb, stateBean)
doTryFlag(lb)
doIfFlag(lb)
stateBean.linesList.add(lb)
handlePostLineFlags(stateBean)
stateBean.perLineOutput = StringBuilder()
stateBean.isLineStart = true
stateBean.indentLevel++
stateBean.perLineStartIndex = stateBean.currentIndex + 1
stateBean.lastChar = r':'
stateBean.currentIndex++
}
public override func dealWithLeftBigBracket(_: StateBean): Unit {
}
public override func dealWithRightBigBracket(_: StateBean): Unit {
}
public func dealWithMultiLineString(stateBean: StateBean): Bool {
let notNullChar: Array<Rune> = stateBean.codeChars.getOrThrow()
let currentIndex: Int64 = stateBean.currentIndex
var currChar: Rune = notNullChar[currentIndex]
if (currentIndex >= 2) {
var lastChar = notNullChar[currentIndex - 1]
var lastlastChar = notNullChar[currentIndex - 2]
if (((lastlastChar == r'"' && lastChar == r'"' && currChar == r'"') || (lastlastChar == r'\'' && lastChar ==
r'\'' && currChar == r'\''))) {
if (!stateBean.isInMultiString) {
stateBean.isInMultiString = true
stateBean.multiStringQuote = currChar
var perStr = ""
if (currChar == r'"') {
perStr = stateBean.perLineOutput.toString().removeSuffix("\"\"\"")
} else {
perStr = stateBean.perLineOutput.toString().removeSuffix("'''")
}
if (notNullChar.size > currentIndex + 3) {
stateBean.currentIndex += 3
let newcurrentIndex = stateBean.currentIndex
lastlastChar = notNullChar[newcurrentIndex - 2]
lastChar = notNullChar[newcurrentIndex - 1]
currChar = notNullChar[newcurrentIndex]
stateBean.perLineOutput.append(lastlastChar)
stateBean.perLineOutput.append(lastChar)
while (!(lastlastChar == stateBean.multiStringQuote && lastChar == stateBean.multiStringQuote &&
currChar == stateBean.multiStringQuote)) {
if (stateBean.currentIndex == stateBean.codeChars.getOrThrow().size - 1) {
break
}
stateBean.currentIndex++
stateBean.perLineOutput.append(currChar)
currChar = stateBean.codeChars.getOrThrow()[stateBean.currentIndex]
lastChar = stateBean.codeChars.getOrThrow()[stateBean.currentIndex - 1]
lastlastChar = stateBean.codeChars.getOrThrow()[stateBean.currentIndex - 2]
}
} else {
stateBean.isInMultiString = false
stateBean.multiStringQuote = r" "
return false
}
let lineEndIndex: Int64 = stateBean.currentIndex
var lineCodeAll: String = String(
stateBean.codeChars.getOrThrow().slice(currentIndex - 2, lineEndIndex - currentIndex + 2 + 1))
if (perStr.trimAscii().size > 0) {
let lb: LineBean = LineBean()
lb.codeLine = perStr
lb.indentLevel = stateBean.indentLevel
setCommonFields(lb, stateBean)
doTryFlag(lb)
doIfFlag(lb)
stateBean.linesList.add(lb)
stateBean.perLineOutput = StringBuilder()
}
let lineCodeList: Array<String> = lineCodeAll.split("\n")
for (index in 0..lineCodeList.size) {
let lb: LineBean = LineBean()
lb.codeLine = lineCodeList[index]
if (index == 0) {
lb.isFirstMultiCommentLine = true
lb.multilineCommentisAfterChangeLine = true
}
lb.indentLevel = stateBean.indentLevel
setCommonFields(lb, stateBean)
lb.isInMultiString = stateBean.isInMultiString
stateBean.linesList.add(lb)
stateBean.perLineOutput = StringBuilder()
}
handlePostLineFlags(stateBean)
stateBean.isLineStart = true
stateBean.perLineStartIndex = stateBean.currentIndex + 1
stateBean.lastChar = r'\n'
stateBean.currentIndex++
stateBean.multiStringQuote = r" "
stateBean.isInMultiString = false
return true
} else {
return false
}
} else {
return false
}
} else {
return false
}
}
public override func dealWithSingleLineComment(_: StateBean, _: String): Unit {
}
public override func dealWithMultiLineComment(_: StateBean, _: String): Unit {
}
public override func dealWithMacro(stateBean: StateBean): Unit {
stateBean.isInMacro = true
let lineStartIndex: Int64 = stateBean.currentIndex
var currChar: Rune = stateBean.codeChars.getOrThrow()[stateBean.currentIndex]
while (currChar != r'\n') {
if (stateBean.currentIndex == stateBean.codeChars.getOrThrow().size - 1) {
break
}
stateBean.currentIndex++
currChar = stateBean.codeChars.getOrThrow()[stateBean.currentIndex]
stateBean.perLineOutput.append(currChar)
}
let lineEndIndex: Int64 = stateBean.currentIndex
let lineCode: String = String(
stateBean.codeChars.getOrThrow().slice(lineStartIndex, lineEndIndex - lineStartIndex + 1))
let lb = LineBean()
lb.codeLine = lineCode
lb.indentLevel = stateBean.indentLevel
setCommonFields(lb, stateBean)
stateBean.linesList.add(lb)
handlePostLineFlags(stateBean)
stateBean.perLineOutput = StringBuilder()
stateBean.isLineStart = true
stateBean.perLineStartIndex = stateBean.currentIndex + 1
stateBean.lastChar = r'\n'
stateBean.currentIndex++
stateBean.isInMacro = false
}
public override func dealWithAccessPublic(_: StateBean): Bool {
return false
}
public override func dealWithAccessPrivate(_: StateBean): Bool {
return false
}
public override func dealWithAccessProtected(_: StateBean): Bool {
return false
}
public override func dealWithString(stateBean: StateBean): Unit {
let notNullChar: Array<Rune> = stateBean.codeChars.getOrThrow()
let currentIndex: Int64 = stateBean.currentIndex
let currChar: Rune = notNullChar[currentIndex]
var lastChar: Rune = r' '
if (currentIndex - 1 >= 0) {
lastChar = notNullChar[currentIndex - 1]
}
if ((currChar == r'"' || currChar == r'\'') && !stateBean.isInString) {
stateBean.stringQuote = currChar
stateBean.isInString = true
return
}
if (stateBean.isInString && currChar == stateBean.stringQuote && lastChar != r'\\') {
stateBean.isInString = false
stateBean.stringQuote = r' '
return
}
if (stateBean.isInString && currChar == r'\n') {
stateBean.isInString = false
stateBean.stringQuote = r' '
return
}
}
public func dealWithReturn(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "return", 6)) {
stateBean.isInRetuen = true
stateBean.isLastLineReturn = true
}
}
public func dealWithContinue(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "continue", 8)) {
stateBean.isInContinue = true
}
}
public func dealWithBreak(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "break", 5)) {
stateBean.isInBreak = true
}
}
public func dealWithExcept(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "except", 6)) {
stateBean.isInExcept = true
}
}
public func dealWithElif(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "elif", 4)) {
stateBean.isInElif = true
}
}
public func dealWithElse(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "else", 4)) {
stateBean.isInElse = true
}
}
public func dealWithDef(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "def ", 4)) {
stateBean.isInDef = true
}
}
public func dealWithImport(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "import ", 7)) {
stateBean.isInImport = true
}
}
public func dealWithClass(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, "class ", 6)) {
stateBean.isInClass = true
stateBean.isHasClass = true
}
}
public func dealWithMain(stateBean: StateBean): Unit {
if (matchKwEndingAt(stateBean, " __name__", 9)) {
stateBean.isInMain = true
}
}
func matchKwEndingAt(stateBean: StateBean, kw: String, kwLen: Int64): Bool {
let chars = stateBean.codeChars.getOrThrow()
let ci = stateBean.currentIndex
if (ci < kwLen - 1 || chars.size <= ci) { return false }
for (i in 0..kwLen) {
if (chars[ci - kwLen + 1 + i].toAsciiLowerCase() != kw.toRuneArray()[i].toAsciiLowerCase()) { return false }
}
return true
}
func createLineBean(stateBean: StateBean, offset: Int64): LineBean {
let lb = LineBean()
let start = stateBean.perLineStartIndex
let end = stateBean.currentIndex
let codeChars = stateBean.codeChars.getOrThrow()
let safeEnd = min(end, codeChars.size - 1)
lb.codeLine = String(codeChars.slice(start, safeEnd - start + 1 - offset))
lb.indentLevel = stateBean.indentLevel
return lb
}
func setCommonFields(lb: LineBean, stateBean: StateBean): Unit {
lb.smallBracketDouble = stateBean.smallBracketDouble
lb.middleBracketDouble = stateBean.middleBracketDouble
lb.sharpBracketDouble = stateBean.sharpBracketDouble
lb.isInString = stateBean.isInString
lb.isInMacro = stateBean.isInMacro
}
func setLineFlagsAndIndent(lineBean: LineBean, stateBean: StateBean): Unit {
if (stateBean.isInExcept) {
if (arrayListFlagTry.size > 0) {
let tryflagBean = arrayListFlagTry.get(arrayListFlagTry.size - 1).getOrThrow()
stateBean.indentLevel = tryflagBean.flagIndent
lineBean.indentLevel = stateBean.indentLevel
arrayListFlagTry.remove(at: arrayListFlagTry.size - 1)
} else {
lineBean.indentLevel = stateBean.indentLevel
}
stateBean.isInExcept = false
} else if (stateBean.isInElif) {
if (arrayListFlagIf.size > 0) {
let ifFlagBean = arrayListFlagIf.get(arrayListFlagIf.size - 1).getOrThrow()
stateBean.indentLevel = ifFlagBean.flagIndent
lineBean.indentLevel = stateBean.indentLevel
} else {
lineBean.indentLevel = stateBean.indentLevel
}
stateBean.isInElif = false
} else if (stateBean.isInElse) {
if (arrayListFlagIf.size > 0) {
let ifFlagBean = arrayListFlagIf.get(arrayListFlagIf.size - 1).getOrThrow()
stateBean.indentLevel = ifFlagBean.flagIndent
lineBean.indentLevel = stateBean.indentLevel
arrayListFlagIf.remove(at: arrayListFlagIf.size - 1)
} else {
lineBean.indentLevel = stateBean.indentLevel
}
stateBean.isInElse = false
} else if (stateBean.isInDef) {
stateBean.indentLevel = if(stateBean.isHasClass) { 1 } else { 0 }
lineBean.indentLevel = stateBean.indentLevel
stateBean.isInDef = false
} else if (stateBean.isInImport) {
stateBean.indentLevel = 0
lineBean.indentLevel = stateBean.indentLevel
stateBean.isInImport = false
} else if (stateBean.isInClass) {
stateBean.indentLevel = 0
lineBean.indentLevel = stateBean.indentLevel
stateBean.isInClass = false
} else if (stateBean.isInMain) {
stateBean.indentLevel = 0
lineBean.indentLevel = stateBean.indentLevel
stateBean.isInMain = false
} else {
lineBean.indentLevel = stateBean.indentLevel
}
}
func handlePostLineFlags(stateBean: StateBean): Unit {
if (stateBean.isInRetuen) {
stateBean.indentLevel--
stateBean.isInRetuen = false
} else {
stateBean.isLastLineReturn = false
}
if (stateBean.isInContinue) {
stateBean.indentLevel--
stateBean.isInContinue = false
}
if (stateBean.isInBreak) {
stateBean.indentLevel--
stateBean.isInBreak = false
}
}
public override func dealWithFor(_: StateBean): Unit {
}
public func dealWithSmallBracket(stateBean: StateBean): Unit {
let notNullChar: Array<Rune> = stateBean.codeChars.getOrThrow()
let currentIndex: Int64 = stateBean.currentIndex
let currChar: Rune = notNullChar[currentIndex]
if (currChar == r'(') {
stateBean.isInSmallBracket = true
stateBean.smallBracketDoublepy++
return
}
if (stateBean.isInSmallBracket) {
let currChar: Rune = notNullChar[currentIndex]
if (currChar == r'(') {
stateBean.smallBracketDoublepy++
}
if (currChar == r')') {
stateBean.smallBracketDoublepy--
if (stateBean.smallBracketDoublepy == 0) {
stateBean.isInSmallBracket = false
}
}
}
}
public func dealWithBigBracket(stateBean: StateBean): Unit {
let notNullChar: Array<Rune> = stateBean.codeChars.getOrThrow()
let currentIndex: Int64 = stateBean.currentIndex
let currChar: Rune = notNullChar[currentIndex]
if (currChar == r'{') {
stateBean.isInBigBracket = true
stateBean.bigBracketDoublepy++
return
}
if (stateBean.isInBigBracket) {
let currChar: Rune = notNullChar[currentIndex]
if (currChar == r'{') {
stateBean.bigBracketDoublepy++
}
if (currChar == r'}') {
stateBean.bigBracketDoublepy--
if (stateBean.bigBracketDoublepy == 0) {
stateBean.isInBigBracket = false
}
}
}
}
public override func dealWithSemicolon(stateBean: StateBean): Unit {
let lb = createLineBean(stateBean, 0)
setLineFlagsAndIndent(lb, stateBean)
setCommonFields(lb, stateBean)
lb.isInFor = stateBean.isInFor
doTryFlag(lb)
doIfFlag(lb)
stateBean.linesList.add(lb)
handlePostLineFlags(stateBean)
if (stateBean.isInFor) {
stateBean.isInFor = false
}
stateBean.perLineOutput = StringBuilder()
stateBean.isLineStart = true
stateBean.perLineStartIndex = stateBean.currentIndex + 1
stateBean.lastChar = r';'
stateBean.currentIndex++
}
func formatCode(rawCode: String, cfg: FormatConfig): String {
let runCode = rawCode.replace("\r\n","\n")
let stateBean: StateBean = StateBean()
stateBean.linesList = ArrayList<LineBean>()
stateBean.codeChars = runCode.toRuneArray()
if (let Some(i) <- stateBean.codeChars) {
let len = i.size
if (len == 0) {
return ""
}
while (stateBean.currentIndex < len) {
let currChar = i[stateBean.currentIndex]
stateBean.perLineOutput.append(currChar)
if (currChar == r'#' && stateBean.isLineStart) {
dealWithMacro(stateBean)
continue
}
let res = dealWithMultiLineString(stateBean)
if (res) {
continue
}
dealWithString(stateBean)
if (!stateBean.isInString) {
dealWithSmallBracket(stateBean)
dealWithBigBracket(stateBean)
}
if (!stateBean.isInString) {
dealWithDef(stateBean)
}
if (!stateBean.isInString) {
dealWithImport(stateBean)
}
if (!stateBean.isInString) {
dealWithClass(stateBean)
}
if (!stateBean.isInString) {
dealWithMain(stateBean)
}
if (!stateBean.isInString) {
dealWithReturn(stateBean)
}
if (!stateBean.isInString) {
dealWithContinue(stateBean)
}
if (!stateBean.isInString) {
dealWithBreak(stateBean)
}
if (!stateBean.isInString) {
dealWithExcept(stateBean)
}
if (!stateBean.isInString) {
dealWithElif(stateBean)
}
if (!stateBean.isInString) {
dealWithElse(stateBean)
}
if (currChar == r':' && !stateBean.isInMacro && !stateBean.isInString && !stateBean.isInSmallBracket &&
!stateBean.isInBigBracket) {
dealWithColon(stateBean)
continue
}
if (currChar == r';' && !stateBean.isInMacro && !stateBean.isInString) {
dealWithSemicolon(stateBean)
continue
}
if (currChar == r'\n' && !stateBean.isInString) {
dealWithNewLine(stateBean)
stateBean.isLineStart = true
} else {
if (stateBean.isLineStart && (currChar == r' ' || currChar == r'\t')) {
stateBean.isLineStart = true
} else {
stateBean.isLineStart = false
}
}
stateBean.lastChar = currChar
stateBean.currentIndex++
}
dealWithNewLine(stateBean)
removeOnlyChangeLine(stateBean)
removediscard(stateBean)
for (i in 0..stateBean.linesList.size) {
let lineBean: LineBean = stateBean.linesList[i]
if (lineBean.codeLine.trimAscii() == ";" && !lineBean.isInMultiString && !lineBean.isInMacro) {
if (i > 0) {
let lastLineBean: LineBean = stateBean.linesList[i - 1]
let stringbuilder: StringBuilder = StringBuilder()
stringbuilder.append(lastLineBean.codeLine)
stringbuilder.append(lineBean.codeLine)
lastLineBean.codeLine = stringbuilder.toString()
lineBean.isDiscarded = true
}
}
}
removediscard(stateBean)
for (i in 0..stateBean.linesList.size) {
let lineBean: LineBean = stateBean.linesList[i]
let codeStr = lineBean.codeLine.trimAscii().replace(" ", "")
if (codeStr.startsWith(");") && !lineBean.isInMultiString && !lineBean.isInMacro) {
if (i > 0) {
let lastLineBean: LineBean = stateBean.linesList[i - 1]
if (lastLineBean.codeLine.trimAscii().endsWith("}")) {
let stringbuilder: StringBuilder = StringBuilder()
stringbuilder.append(lastLineBean.codeLine)
stringbuilder.append(lineBean.codeLine)
lastLineBean.codeLine = stringbuilder.toString()
lineBean.isDiscarded = true
}
}
}
}
removediscard(stateBean)
for (i in 0..stateBean.linesList.size) {
let lineBean: LineBean = stateBean.linesList[i]
let codeStr = lineBean.codeLine.trimAscii().replace(" ", "")
if (codeStr.endsWith("]") && !codeStr.contains("[") && !lineBean.isInMultilineComment &&
!lineBean.isInSinglelineComment) {
if (i > 0) {
let lastLineBean: LineBean = stateBean.linesList[i - 1]
if (lastLineBean.codeLine.trimAscii().endsWith(",")) {
let stringbuilder: StringBuilder = StringBuilder()
stringbuilder.append(lastLineBean.codeLine.trimAscii())
stringbuilder.append(lineBean.codeLine.trimAscii())
lastLineBean.codeLine = stringbuilder.toString().replace("\n", "")
lineBean.isDiscarded = true
}
}
}
}
removediscard(stateBean)
let usefulList: ArrayList<LineBean> = stateBean.linesList
for (item in usefulList) {
item.codeLine = item.codeLine.trimAscii()
}
for (index in 0..usefulList.size) {
let item: LineBean = usefulList[index]
addIndent(stateBean.output, item.indentLevel, cfg)
stateBean.output.append(item.codeLine)
if (index != usefulList.size - 1) {
stateBean.output.append("\n")
}
}
return stateBean.output.toString()
} else {
return ""
}
}
}