Files
hank/hank-godot/scripts/HankBuffer.gd
Nat Quayle Nelson b0a3c0b3d9
Some checks failed
/ test (push) Failing after 41s
Make hank work in GDScript
2025-10-30 21:42:19 -05:00

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)