Cleanup and document core APIs in C, JS, and Python.
This commit is contained in:
@@ -1,35 +1,63 @@
|
||||
from typing import TypedDict
|
||||
|
||||
# Holds the parsed information from each line.
|
||||
class LineData(TypedDict):
|
||||
line: str
|
||||
# Which character is being used for indentation. Avoids having to specify it on each terrace_parse_line call.
|
||||
indent: str
|
||||
# How many indent characters are present in the current line before the first non-indent character.
|
||||
level: int
|
||||
# The number of characters before the start of the line's "head" section.
|
||||
# (Normally the same as `level`)
|
||||
offsetHead: int
|
||||
# The number of characters before the start of the line's "tail" section.
|
||||
offsetTail: int
|
||||
|
||||
def createLineData(line: str = '', indent: str = ' ') -> LineData:
|
||||
return { "line": line, "indent": indent, "level": 0, "offsetHead": 0, "offsetTail": 0 }
|
||||
def createLineData(indent: str = ' ') -> LineData:
|
||||
"""
|
||||
Initialize a LineData instance with default values.
|
||||
|
||||
def parseLine(lineData: LineData) -> LineData:
|
||||
# if ((typeof lineData !== 'object' || !lineData) || typeof lineData.level !== 'number') throw new Error(`'lineData' must be an object with string line and numeric level properties`)
|
||||
# if (typeof lineData.indent !== 'string' || lineData.indent.length === 0 || lineData.indent.length > 1) throw new Error(`'lineData.indent' must be a single-character string`)
|
||||
# if (typeof lineData.line !== 'string') throw new Error(`'lineData.line' must be a string`)
|
||||
Parameters
|
||||
----------
|
||||
indent : str
|
||||
The character to use for indenting lines. ONLY ONE CHARACTER IS CURRENTLY PERMITTED.
|
||||
Returns
|
||||
-------
|
||||
LineData
|
||||
A LineData dict with the specified indent character and all other values initialized to 0.
|
||||
"""
|
||||
return { "indent": indent, "level": 0, "offsetHead": 0, "offsetTail": 0 }
|
||||
|
||||
level = 0
|
||||
def parseLine(line: str, lineData: LineData):
|
||||
"""
|
||||
Core Terrace parser function, sets level, offsetHead, and offsetTail in a LineData object based on the current line.
|
||||
Note that this is a C-style function, lineData is treated as a reference and mutated in-place.
|
||||
|
||||
# Repeat previous level for blank lines.
|
||||
if len(lineData['line']) == 0:
|
||||
lineData['level'] = lineData['level']
|
||||
Parameters
|
||||
----------
|
||||
line : str
|
||||
A string containing a line to parse. Shouldn't end with a newline.
|
||||
lineData: LineData
|
||||
A LineData dict to store information about the current line in. **Mutated in-place!**
|
||||
"""
|
||||
|
||||
# Blank lines have no characters, the newline should be stripped off.
|
||||
# Special case handling for these allows them to be parsed quickly.
|
||||
if len(line) == 0:
|
||||
# Empty lines are treated as having the same level as the previous line, so lineData.line is not updated.
|
||||
lineData['offsetHead'] = 0
|
||||
lineData['offsetTail'] = 0
|
||||
else:
|
||||
while level < len(lineData['line']) and lineData['line'][level] == lineData['indent'] and level <= lineData['level'] + 1:
|
||||
# Count the number of indent characters in the current line.
|
||||
level = 0
|
||||
while level < len(line) and line[level] == lineData['indent']:
|
||||
level += 1
|
||||
lineData['level'] = level
|
||||
|
||||
# Set offsetHead and offsetTail to level to start with.
|
||||
# offsetHead should always be equal to level, and offsetTail will always be equal to or greater than level.
|
||||
lineData['offsetHead'] = level
|
||||
lineData['offsetTail'] = level
|
||||
|
||||
while lineData['offsetTail'] < len(lineData['line']) and lineData['line'][lineData['offsetTail']] != ' ':
|
||||
lineData['offsetTail'] += 1
|
||||
|
||||
return lineData
|
||||
# Increment offsetTail until we encounter a space character (start of tail) or reach EOL (no tail present).
|
||||
while lineData['offsetTail'] < len(line) and line[lineData['offsetTail']] != ' ':
|
||||
lineData['offsetTail'] += 1
|
||||
@@ -14,33 +14,21 @@ def next():
|
||||
return line.rstrip('\n') if len(line) > 0 else None
|
||||
|
||||
def linedata_basic (indent):
|
||||
lineData = createLineData('', indent)
|
||||
lineData = createLineData(indent)
|
||||
|
||||
while (l := next()) != None:
|
||||
lineData['line'] = l
|
||||
parseLine(lineData)
|
||||
while (line := next()) != None:
|
||||
parseLine(line, lineData)
|
||||
print("| level {level} | indent {indent} | offsetHead {offsetHead} | offsetTail {offsetTail} | line {line} |".format(
|
||||
level = lineData['level'], indent = lineData['indent'], offsetHead = lineData['offsetHead'], offsetTail = lineData['offsetTail'], line = lineData['line']
|
||||
))
|
||||
|
||||
def linedata_tabs ():
|
||||
lineData = createLineData('', '\t')
|
||||
|
||||
while (l := next()) != None:
|
||||
lineData['line'] = l
|
||||
parseLine(lineData)
|
||||
print("| level {level} | indent {indent} | offsetHead {offsetHead} | offsetTail {offsetTail} | line {line} |".format(
|
||||
level = lineData['level'], indent = lineData['indent'], offsetHead = lineData['offsetHead'], offsetTail = lineData['offsetTail'], line = lineData['line']
|
||||
level = lineData['level'], indent = lineData['indent'], offsetHead = lineData['offsetHead'], offsetTail = lineData['offsetTail'], line = line
|
||||
))
|
||||
|
||||
def linedata_head_tail ():
|
||||
lineData = createLineData('')
|
||||
lineData = createLineData()
|
||||
|
||||
while (l := next()) != None:
|
||||
lineData['line'] = l
|
||||
parseLine(lineData)
|
||||
head = lineData['line'][lineData['offsetHead']:lineData['offsetTail']] if len(lineData['line']) > lineData['offsetHead'] else ''
|
||||
tail = lineData['line'][lineData['offsetTail'] + 1:] if len(lineData['line']) > lineData['offsetTail'] + 1 else ''
|
||||
while (line := next()) != None:
|
||||
parseLine(line, lineData)
|
||||
head = line[lineData['offsetHead']:lineData['offsetTail']] if len(line) > lineData['offsetHead'] else ''
|
||||
tail = line[lineData['offsetTail'] + 1:] if len(line) > lineData['offsetTail'] + 1 else ''
|
||||
|
||||
print("| head {head} | tail {tail} |".format(
|
||||
head = head, tail = tail
|
||||
|
||||
Reference in New Issue
Block a user