63 lines
2.5 KiB
Python
63 lines
2.5 KiB
Python
from typing import TypedDict
|
|
|
|
# Holds the parsed information from each line.
|
|
class LineData(TypedDict):
|
|
# 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(indent: str = ' ') -> LineData:
|
|
"""
|
|
Initialize a LineData instance with default values.
|
|
|
|
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 }
|
|
|
|
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.
|
|
|
|
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:
|
|
# 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
|
|
|
|
# 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 |