"""Module used to manage the context of a knitout interpreter."""
from __future__ import annotations
from knit_graphs.Knit_Graph import Knit_Graph
from virtual_knitting_machine.Knitting_Machine import Knitting_Machine
from knitout_interpreter.knitout_execution import Knitout_Executer
from knitout_interpreter.knitout_language.Knitout_Parser import parse_knitout
from knitout_interpreter.knitout_operations.Header_Line import Knitout_Header_Line, Knitting_Machine_Header
from knitout_interpreter.knitout_operations.Knitout_Line import Knitout_Line, Knitout_Version_Line, Knitout_Comment_Line
from knitout_interpreter.knitout_operations.knitout_instruction import Knitout_Instruction
[docs]
def process_knitout_instructions(codes: list[Knitout_Line]) -> (
tuple)[Knitout_Version_Line, list[Knitout_Header_Line], list[Knitout_Instruction], list[Knitout_Comment_Line]]:
"""Separate list of knitout codes into components of a program for execution.
Args:
codes: List of knitout instructions to separate into program components.
Returns:
A tuple containing:
- Version line for the knitout program
- List of header lines
- List of instruction lines
- List of comment lines
"""
version_line: Knitout_Version_Line = Knitout_Version_Line(-1) # -1 set to undo default if no version line is provided.
head: list[Knitout_Header_Line] = []
instructions: list[Knitout_Instruction] = []
comments: list[Knitout_Comment_Line] = []
for code in codes:
if isinstance(code, Knitout_Version_Line):
assert version_line.version == code.version or version_line.version < 0, f"Cannot have multiple versions of knitout {version_line} and {code}"
version_line = code
elif isinstance(code, Knitout_Header_Line):
head.append(code)
elif isinstance(code, Knitout_Instruction):
instructions.append(code)
elif isinstance(code, Knitout_Comment_Line):
comments.append(code)
else:
assert False, f"Cannot process code {code}"
if version_line.version < 0:
version_line = Knitout_Version_Line(2, "Version defaulted to 2")
return version_line, head, instructions, comments
[docs]
class Knitout_Context:
"""Maintains information about the state of a knitting process as knitout instructions are executed."""
def __init__(self) -> None:
self.machine_state: Knitting_Machine = Knitting_Machine()
self.executed_knitout: list[Knitout_Line] = []
self.version_line: Knitout_Version_Line | None = None
self.executed_header: Knitting_Machine_Header = Knitting_Machine_Header(self.machine_state)
self.executed_instructions: list[Knitout_Instruction] = []
@property
def version(self) -> int:
"""Get the knitout version of the current context.
Returns:
The knitout version number, defaults to 2 if no version is set.
"""
if self.version_line is not None:
return int(self.version_line.version)
else:
return 2
@version.setter
def version(self, version_line: Knitout_Version_Line) -> None:
"""Set the version line for the current context.
This will override any existing version.
Args:
version_line: The version line to set for this context.
"""
self.version_line = version_line
[docs]
def execute_instructions(self, instructions: list[Knitout_Line]) -> None:
"""Execute the instruction set on the machine state defined by the current header.
Args:
instructions: Instructions to execute on the knitting machine.
"""
execution = Knitout_Executer(instructions=instructions, knitting_machine=self.machine_state, knitout_version=self.version)
self.executed_instructions = execution.executed_instructions
[docs]
def execute_knitout(self, version_line: Knitout_Version_Line,
header_declarations: list[Knitout_Header_Line],
instructions: list[Knitout_Instruction]) -> tuple[list[Knitout_Line], Knitting_Machine, Knit_Graph]:
"""Execute the given knitout organized by version, header, and instructions.
Args:
version_line: The version of knitout to use.
header_declarations: The header to define the knitout file.
instructions: The instructions to execute on the machine.
Returns:
A tuple containing:
- List of knitout instructions that were executed
- Machine state after execution
- Knit graph created by execution
"""
self.version = version_line
self.execute_header(header_declarations)
self.execute_instructions(instructions)
for i, instruction in enumerate(self.executed_instructions):
instruction.original_line_number = i
return self.executed_instructions, self.machine_state, self.machine_state.knit_graph
[docs]
def process_knitout_file(self, knitout_file_name: str) -> tuple[list[Knitout_Line], Knitting_Machine, Knit_Graph]:
"""Parse and process a file of knitout code.
Args:
knitout_file_name: File path containing knitout code to process.
Returns:
A tuple containing:
- List of executed knitout lines
- Knitting machine state after execution
- Knit graph formed by execution
"""
codes = parse_knitout(knitout_file_name, pattern_is_file=True, debug_parser=False, debug_parser_layout=False)
return self.execute_knitout_instructions(codes)
[docs]
def execute_knitout_instructions(self, codes: list[Knitout_Line]) -> tuple[list[Knitout_Line], Knitting_Machine, Knit_Graph]:
"""Execute given knitout instructions.
Args:
codes: List of knitout lines to execute.
Returns:
A tuple containing:
- List of executed knitout lines
- Machine state after execution
- Knit graph created by execution
"""
version, head, instructions, comments = process_knitout_instructions(codes)
return self.execute_knitout(version, head, instructions)