Files
konabot/konabot/plugins/marchtoy/command.py
2026-04-27 23:19:59 +08:00

73 lines
2.2 KiB
Python

"""
raymarch toy
usage: march <scene1> <scene2> ... <sceneN>
<scene> ::= <scene> "." <command>
| <command>
<command> ::= <id>
| <id> "(" <args> ")"
example:
march cube.pos(0, 0, 0).color(red) cam(1.0).pos(1, 1, 1).lookat(0, 0, 0)
"""
from dataclasses import dataclass
import regex as re
from dataclasses import dataclass
@dataclass
class Command:
id: str
args: list[str]
class CommandChainParser:
CHAIN_PATTERN = r"^(([a-zA-Z0-9]+(?:\(([^()]*|(?1)+)(\s*\,\s*(?1))*\))?)(\.(?1))*)"
def __init__(self, _command_chain: str) -> None:
self.command_chain = _command_chain
def __iter__(self):
return self
def __next__(self):
if query := re.match(CommandChainParser.CHAIN_PATTERN, self.command_chain):
cmd_chain = query[0]
self.command_chain = self.command_chain[len(cmd_chain) + 1 :]
return cmd_chain
raise StopIteration
class CommandParser:
CMD_PATTERN = r"^[a-zA-Z]+(?:\(([0-9.\-+]+|(([a-zA-Z0-9]+(?:\(([^()]*|(?1)+)(\s*\,\s*(?1))*\))?)(\.(?1))*))(\s*\,\s*(?1))*\))?"
ID_PATTERN = r"^[a-zA-Z]+(?=\(|\.|$)"
ARG_PATTERN = CommandChainParser.CHAIN_PATTERN
TRIM_PATTERN = r"^\s*\,\s*"
def __init__(self, _command: str) -> None:
self.command = _command
def __iter__(self):
return self
def __next__(self):
if query := re.match(CommandParser.CMD_PATTERN, self.command):
cmd = query[0]
if cmd_id_qry := re.match(CommandParser.ID_PATTERN, cmd):
id = cmd_id_qry[0]
cmd_args = cmd[len(id) + 1 : -1] # .replace(" ", "").split(",")
args: list[str] = []
self.command = self.command[len(cmd) + 1 :]
while cmd_arg_qry := re.match(CommandParser.ARG_PATTERN, cmd_args):
arg = cmd_arg_qry[0]
args.append(arg)
cmd_args = cmd_args[len(arg) :]
if trim_qry := re.match(CommandParser.TRIM_PATTERN, cmd_args):
cmd_args = cmd_args[len(trim_qry[0]) :]
# while "" in cmd_args:
# cmd_args.remove("")
return Command(id, args)
raise StopIteration