454 lines
12 KiB
GDScript
454 lines
12 KiB
GDScript
class_name HankBuffer
|
|
|
|
var path: String
|
|
var cleanBuffer: String
|
|
var rawBuffer: String
|
|
var line: int
|
|
var column: int
|
|
|
|
func _init(path2: String, rawBuffer2: String, line2: int = 1, column2: int = 1) -> void:
|
|
if (rawBuffer2 == null):
|
|
assert(false, str("Tried to create buffer of path " + path2 + " with null contents: " + rawBuffer2))
|
|
|
|
self.path = path2
|
|
self.rawBuffer = rawBuffer2
|
|
self.cleanBuffer = self.stripComments(rawBuffer2, "//", "\n", false)
|
|
self.cleanBuffer = self.stripComments(self.cleanBuffer, "/*", "*/", true)
|
|
self.line = line2
|
|
self.column = column2
|
|
|
|
func lines() -> Array[String]:
|
|
var _this: String = self.cleanBuffer
|
|
var tempArray: Array[String] = Array(Array(_this.split("\n")), Variant.Type.TYPE_STRING, "", null)
|
|
|
|
self.drop(self.cleanBuffer)
|
|
|
|
return tempArray
|
|
|
|
func stripComments(s: String, o: String, c: String, dc: bool) -> String:
|
|
while (s.find(o) != -1):
|
|
var start: int = s.find(o)
|
|
var end: int = s.find(c, start)
|
|
if (end == -1):
|
|
s = s.substr(0, start)
|
|
else:
|
|
if (dc):
|
|
end += c.length()
|
|
s = s.substr(0, start) + s.substr(end)
|
|
|
|
return s
|
|
|
|
func indexOf(s: String, start: int = 0) -> int:
|
|
return self.cleanBuffer.find(s, start)
|
|
|
|
func everyIndexOf(s: String) -> Array[int]:
|
|
var _gthis: HankBuffer = self
|
|
var tempArray
|
|
|
|
if true:
|
|
var _g: Array[int] = ([] as Array[int])
|
|
if true:
|
|
var _g1: int = 0
|
|
var _g2: int = self.cleanBuffer.length()
|
|
while (_g1 < _g2):
|
|
var tempNumber
|
|
if true:
|
|
_g1 += 1
|
|
tempNumber = _g1 - 1
|
|
var i: int = tempNumber
|
|
_g.push_back(i)
|
|
tempArray = _g
|
|
|
|
var temp = func(i: int) -> bool:
|
|
return _gthis.cleanBuffer[i] == s
|
|
var result: Array[int] = ([] as Array[int])
|
|
|
|
if true:
|
|
var _g: int = 0
|
|
while (_g < tempArray.size()):
|
|
var v: int = tempArray[_g]
|
|
_g += 1
|
|
if (temp.call(v)):
|
|
result.push_back(v)
|
|
|
|
return result
|
|
|
|
func everyRootIndexOf(s: String) -> Array[int]:
|
|
var _gthis: HankBuffer = self
|
|
var tempArray
|
|
|
|
if true:
|
|
var _g: Array[int] = ([] as Array[int])
|
|
if true:
|
|
var _g1: int = 0
|
|
var _g2: Array[int] = self.everyIndexOf(s)
|
|
while (_g1 < _g2.size()):
|
|
var i: int = _g2[_g1]
|
|
_g1 += 1
|
|
_g.push_back(i)
|
|
tempArray = _g
|
|
|
|
var temp = func(i: int) -> bool:
|
|
return _gthis.depthAtIndex("{", "}", i) == 0
|
|
var result: Array[int] = ([] as Array[int])
|
|
|
|
if true:
|
|
var _g: int = 0
|
|
while (_g < tempArray.size()):
|
|
var v: int = tempArray[_g]
|
|
_g += 1
|
|
if (temp.call(v)):
|
|
result.push_back(v)
|
|
|
|
return result
|
|
|
|
func rootIndexOf(s: String) -> int:
|
|
var start: int = 0
|
|
|
|
while (true):
|
|
start = self.indexOf(s, start)
|
|
if (start == -1):
|
|
return -1
|
|
if (self.depthAtIndex("{", "}", start) == 0):
|
|
return start
|
|
start += 1
|
|
|
|
return -1
|
|
|
|
func rootSplit(delimiter: String) -> Array[String]:
|
|
var rootIndices: Array[int] = self.everyRootIndexOf(delimiter)
|
|
|
|
if (rootIndices.size() == 0):
|
|
return ([self.cleanBuffer] as Array[String])
|
|
|
|
var substrs: Array[String] = ([] as Array[String])
|
|
var lastIdx: int = 0
|
|
var _g: int = 0
|
|
|
|
while (_g < rootIndices.size()):
|
|
var i: int = rootIndices[_g]
|
|
_g += 1
|
|
substrs.push_back(self.cleanBuffer.substr(lastIdx, i - lastIdx))
|
|
lastIdx = i + 1
|
|
|
|
substrs.push_back(self.cleanBuffer.substr(lastIdx))
|
|
|
|
return substrs
|
|
|
|
func length() -> int:
|
|
return self.cleanBuffer.length()
|
|
|
|
func position() -> Position:
|
|
return Position.new(self.path, self.line, self.column)
|
|
|
|
func peekAhead(start: int, length: int) -> String:
|
|
return self.cleanBuffer.substr(start, length)
|
|
|
|
func peekUntil(terminators: Array[String], eofTerminates: bool = false, raw: bool = false) -> Variant:
|
|
var tempString
|
|
|
|
if (raw):
|
|
tempString = self.rawBuffer
|
|
else:
|
|
tempString = self.cleanBuffer
|
|
|
|
var buffer: String = tempString
|
|
|
|
if (buffer.length() == 0):
|
|
return { "_index": 1 }
|
|
|
|
var index: int = buffer.length()
|
|
var whichTerminator: String = ""
|
|
var _g: int = 0
|
|
|
|
while (_g < terminators.size()):
|
|
var terminator: String = terminators[_g]
|
|
_g += 1
|
|
var nextIndex: int = buffer.find(terminator)
|
|
if (nextIndex != -1 && nextIndex < index):
|
|
index = nextIndex
|
|
whichTerminator = terminator
|
|
|
|
var tempResult
|
|
|
|
if (index < buffer.length() || eofTerminates):
|
|
tempResult = { "_index": 0, "v": {
|
|
"output": buffer.substr(0, index),
|
|
"terminator": whichTerminator
|
|
} }
|
|
else:
|
|
tempResult = { "_index": 1 }
|
|
|
|
return tempResult
|
|
|
|
func dropRaw(s: String) -> void:
|
|
var actual: String = self.rawBuffer.substr(0, s.length())
|
|
|
|
if (actual != s):
|
|
assert(false, str("Expected to drop \"" + s + "\" but was \"" + actual + "\""))
|
|
|
|
var lines: Array[String] = Array(Array(s.split("\n")), Variant.Type.TYPE_STRING, "", null)
|
|
|
|
if (lines.size() > 1):
|
|
self.line += lines.size() - 1
|
|
self.column = lines[lines.size() - 1].length() + 1
|
|
else:
|
|
self.column += lines[0].length()
|
|
|
|
self.rawBuffer = self.rawBuffer.substr(s.length())
|
|
|
|
func dropClean(s: String) -> void:
|
|
var actual: String = self.cleanBuffer.substr(0, s.length())
|
|
|
|
if (actual != s):
|
|
assert(false, str("Expected to drop \"" + s + "\" but was \"" + actual + "\""))
|
|
|
|
self.cleanBuffer = self.cleanBuffer.substr(s.length())
|
|
|
|
func drop(s: String) -> void:
|
|
var untilNextComment: Variant = self.peekUntil((["//", "/*"] as Array[String]), false, true)
|
|
|
|
if (untilNextComment._index == 0):
|
|
var _g: Variant = untilNextComment.v
|
|
var _g1: String = _g.get("output")
|
|
var _g2: String = _g.get("terminator")
|
|
var rawS: String = _g1
|
|
var commentOpener: String = _g2
|
|
if (rawS.length() < s.length()):
|
|
var tempString
|
|
match (commentOpener):
|
|
"/*":
|
|
tempString = "*/"
|
|
"//":
|
|
tempString = "\n"
|
|
_:
|
|
assert(false, str("FUBAR"))
|
|
var commentTerminator: String = tempString
|
|
self.dropRaw(rawS + commentOpener)
|
|
self.dropClean(rawS)
|
|
var untilEndOfComment: Variant = self.peekUntil(([commentTerminator] as Array[String]), true, true)
|
|
if (untilEndOfComment._index == 0):
|
|
var _g3: Variant = untilEndOfComment.v
|
|
var _g4: String = _g3.get("output")
|
|
var _g5: String = _g3.get("terminator")
|
|
var comment: String = _g4
|
|
self.dropRaw(comment)
|
|
if (commentTerminator != "\n"):
|
|
self.dropRaw(commentTerminator)
|
|
var rest: String = s.substr(rawS.length())
|
|
self.drop(rest)
|
|
else:
|
|
assert(false, str("FUBAR"))
|
|
else:
|
|
self.dropClean(s)
|
|
self.dropRaw(s)
|
|
else:
|
|
self.dropClean(s)
|
|
self.dropRaw(s)
|
|
|
|
func takeUntil(terminators: Array[String], eofTerminates: bool = false, dropTerminator: bool = true) -> Variant:
|
|
var tempResult
|
|
|
|
if true:
|
|
var _g: Variant = self.peekUntil(terminators, eofTerminates, false)
|
|
match (_g._index):
|
|
0:
|
|
var _g2: Variant = _g.v
|
|
var _g1: String = _g2.get("output")
|
|
var _g3: String = _g2.get("terminator")
|
|
var s: String = _g1
|
|
var t: String = _g3
|
|
self.drop(s)
|
|
if (dropTerminator):
|
|
self.drop(t)
|
|
tempResult = { "_index": 0, "v": {
|
|
"output": s,
|
|
"terminator": t
|
|
} }
|
|
1:
|
|
tempResult = { "_index": 1 }
|
|
|
|
return tempResult
|
|
|
|
func peek(chars: int) -> String:
|
|
if (self.cleanBuffer.length() < chars):
|
|
assert(false, str("Not enough characters left in buffer."))
|
|
|
|
var data: String = self.cleanBuffer.substr(0, chars)
|
|
|
|
return data
|
|
|
|
func take(chars: int) -> String:
|
|
var data: String = self.peek(chars)
|
|
|
|
self.drop(data)
|
|
|
|
return data
|
|
|
|
func countConsecutive(s: String) -> int:
|
|
var num: int = 0
|
|
|
|
while (self.cleanBuffer.substr(0, s.length()) == s):
|
|
num += 1
|
|
self.drop(s)
|
|
|
|
return num
|
|
|
|
func expressionIfNext(o: String, c: String) -> Variant:
|
|
if (StringTools.startsWith(self.cleanBuffer, o) && self.cleanBuffer.find(c) != -1):
|
|
self.drop(o)
|
|
var end: int = self.cleanBuffer.find(c)
|
|
var content: String = self.take(end)
|
|
self.drop(c)
|
|
return { "_index": 0, "v": content }
|
|
|
|
return { "_index": 1 }
|
|
|
|
func getLine(trimmed: String, retriever, dropNewline: bool) -> Variant:
|
|
var nextLine: Variant = retriever.call((["\n"] as Array[String]), true, false)
|
|
var tempResult
|
|
|
|
match (nextLine._index):
|
|
0:
|
|
var _g: Variant = nextLine.v
|
|
var _g1: String = _g.get("output")
|
|
var _g2: String = _g.get("terminator")
|
|
var nextLine2: String = _g1
|
|
if (dropNewline && !self.isEmpty()):
|
|
self.drop("\n")
|
|
if (trimmed.find("r") != -1):
|
|
var tempRight
|
|
if true:
|
|
var l: int = nextLine2.length()
|
|
var r: int = 0
|
|
while (r < l && StringTools.isSpace(nextLine2, l - r - 1)):
|
|
r += 1
|
|
if (r > 0):
|
|
tempRight = nextLine2.substr(0, l - r)
|
|
else:
|
|
tempRight = nextLine2
|
|
nextLine2 = tempRight
|
|
if (trimmed.find("l") != -1):
|
|
var tempRight1
|
|
if true:
|
|
var l: int = nextLine2.length()
|
|
var r: int = 0
|
|
while (r < l && StringTools.isSpace(nextLine2, r)):
|
|
r += 1
|
|
if (r > 0):
|
|
tempRight1 = nextLine2.substr(r, l - r)
|
|
else:
|
|
tempRight1 = nextLine2
|
|
nextLine2 = tempRight1
|
|
tempResult = { "_index": 0, "v": nextLine2 }
|
|
1:
|
|
tempResult = { "_index": 1 }
|
|
|
|
return tempResult
|
|
|
|
func peekLine(trimmed: String = "") -> Variant:
|
|
return self.getLine(trimmed, self.peekUntil, false)
|
|
|
|
func takeLine(trimmed: String = "") -> Variant:
|
|
return self.getLine(trimmed, self.takeUntil, true)
|
|
|
|
func skipWhitespace(terminator: String = "") -> void:
|
|
var nextTerm: int = self.cleanBuffer.find(terminator)
|
|
var tempString
|
|
var s: String = self.cleanBuffer
|
|
var l: int = s.length()
|
|
var r: int = 0
|
|
|
|
while (r < l && StringTools.isSpace(s, r)):
|
|
r += 1
|
|
|
|
if (r > 0):
|
|
tempString = s.substr(r, l - r)
|
|
else:
|
|
tempString = s
|
|
|
|
var withoutTerm: int = self.cleanBuffer.length() - (tempString).length()
|
|
var tempNumber
|
|
|
|
if (nextTerm <= 0):
|
|
tempNumber = withoutTerm
|
|
else:
|
|
var v: float = min(nextTerm, withoutTerm)
|
|
tempNumber = int(floor(v))
|
|
|
|
var end: int = tempNumber
|
|
var whitespace: String = self.cleanBuffer.substr(0, end)
|
|
|
|
self.drop(whitespace)
|
|
|
|
func isEmpty() -> bool:
|
|
return self.cleanBuffer.length() == 0
|
|
|
|
func depthAtIndex(o: String, c: String, index: int) -> int:
|
|
var depth: int = 0
|
|
var snippet: String = self.cleanBuffer.substr(0, index)
|
|
var _g: int = 0
|
|
var _g1: int = snippet.length()
|
|
|
|
while (_g < _g1):
|
|
var tempNumber
|
|
_g += 1
|
|
tempNumber = _g - 1
|
|
var i: int = tempNumber
|
|
var whichC: String = snippet[i]
|
|
if (whichC == o):
|
|
depth += 1
|
|
else:
|
|
if (whichC == c):
|
|
depth -= 1
|
|
|
|
return depth
|
|
|
|
func findNestedExpression(o: String, c: String, start: int = 0, throwExceptions: bool = true) -> Variant:
|
|
var startIdx: int = start
|
|
var endIdx: int = start
|
|
var depth: int = 0
|
|
var nextIdx: int = start
|
|
|
|
while true:
|
|
var nextOpeningIdx: int = self.cleanBuffer.find(o, nextIdx)
|
|
var nextClosingIdx: int = self.cleanBuffer.find(c, nextIdx)
|
|
if (nextOpeningIdx == -1 && nextClosingIdx == -1):
|
|
return { "_index": 1 }
|
|
else:
|
|
if (depth == 0 && nextOpeningIdx == -1):
|
|
if (throwExceptions):
|
|
assert(false, str("Your input file " + self.path + " has an expression with an unmatched closing operator " + c))
|
|
else:
|
|
return { "_index": 1 }
|
|
else:
|
|
if (depth != 0 && nextClosingIdx == -1):
|
|
if (throwExceptions):
|
|
assert(false, str("Your input file " + self.path + " has an expression with an unmatched opening operator " + o))
|
|
else:
|
|
return { "_index": 1 }
|
|
else:
|
|
if (nextOpeningIdx != -1 && nextOpeningIdx < nextClosingIdx):
|
|
if (depth == 0):
|
|
startIdx = nextOpeningIdx
|
|
depth += 1
|
|
nextIdx = nextOpeningIdx + o.length()
|
|
else:
|
|
depth -= 1
|
|
nextIdx = nextClosingIdx + c.length()
|
|
endIdx = nextClosingIdx + c.length()
|
|
if !(depth > 0 && nextIdx < self.cleanBuffer.length()):
|
|
break
|
|
|
|
return { "_index": 0, "v": BufferSlice.new(startIdx, endIdx - startIdx, self) }
|
|
|
|
static func Dummy(text: String) -> HankBuffer:
|
|
return HankBuffer.new("_", text, 1, 1)
|
|
|
|
static func FromFile(path2: String, files = null) -> HankBuffer:
|
|
var rawBuffer2: String = ""
|
|
|
|
rawBuffer2 = FileAccess.open(path2, FileAccess.READ).get_as_text()
|
|
|
|
return HankBuffer.new(path2, rawBuffer2)
|