63 lines
1.7 KiB
Python
63 lines
1.7 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-Z0-9]+(?:\(([^()]*|(?1)+)(\s*\,\s*(?1))*\))?))"
|
|
ID_PATTERN = r"^[a-zA-Z]+(?=\(|\.|$)"
|
|
|
|
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):
|
|
cmd_id = cmd_id_qry[0]
|
|
self.command = self.command[len(cmd) + 1 :]
|
|
cmd_args = cmd[len(cmd_id) + 1 : -1]#.replace(" ", "").split(",")
|
|
# while "" in cmd_args:
|
|
# cmd_args.remove("")
|
|
return Command(cmd_id, cmd_args)
|
|
raise StopIteration
|