continued reorganisation

This commit is contained in:
Emile Clark-Boman 2025-06-21 21:29:00 +10:00
parent 6f8a7322f2
commit 0a2d9a5694
22 changed files with 190 additions and 61 deletions

1
bcrypter/cli/__init__.py Normal file
View file

@ -0,0 +1 @@

View file

46
bcrypter/cli/cmd.py Normal file
View file

@ -0,0 +1,46 @@
from bcrypter.lib.result import Result
class Command:
NAME = '[Abstract]Command'
ARGS = []
FLAGS = []
OPTIONS = []
def __init__(self, args: list[string]) -> None:
pass
@classmethod
def parse(cls: Command, cmd: list[str]) -> Result[Command]:
for arg in cmd[1:]:
# flag or option
if arg.startswith('--'):
match = cls._match_arg(arg[2:])
if match
'''
Check whether FLAGS and OPTIONS are defined consistently
(ie no duplicate names or parsing ambiguity)
'''
@classmethod
def _is_well_defined(cls: Command) -> Result[None]:
raise NotImplementedException('Command.is_consistent()')
'''
Attempt to match an arg to its flag or option
NOTE: _match_arg() assumes _is_well_defined() == True
'''
@classmethod
def _match_arg(cls: Command, arg: str) -> Result[None]:
for opt in chain(cls.FLAGS, cls.OPTIONS):
if opt.matches(arg):
return Result.succeed(None)
return Result.fail()
class Builtin(Command):
self.NAME = '[Abstract]Builtin'
def __init__(self,
repl_builtins: list[Builtin],
repl_cmds: list[Command]) -> None:
super().__init__()
self._repl_builtins = repl_builtins
self._repl_cmds = repl_cmds

View file

21
bcrypter/cli/opt.py Normal file
View file

@ -0,0 +1,21 @@
from enum import Enum
class OptType(Enum):
AbstractOpt # only used by Opt
Flag
Option
class Opt:
_TYPE: OptType = OptType.AbstractOpt
def __init__(self, *args) -> None:
pass
class Flag(Opt):
_TYPE: OptType = OptType.Flag
def __init__(self, *args) -> None:
super().__init__(*args)
class Option(Opt):
_TYPE: OptType = OptType.Option
def __init__(self, *args) -> None:
super().__init__(*args)

42
bcrypter/cli/repl.py Normal file
View file

@ -0,0 +1,42 @@
import readline # GNU readline (ie allows input() history buffer)
from itertools import chain
from bcrypter.cli.builtins import *
from bcrypter.cli.commands import *
from bcrypter.lib.result import Result
from bcrypter.exceptions import CmdDeclarationError
class REPL:
_PROMPT = '>> '
_DEFAULT_HISTORY_FILE = '.bcrypter_history'
_BUILTINS = [
BuiltinHelp(),
]
_COMMANDS = [
]
def __init__(self, history_file: str = _DEFAULT_HISTORY_FILE) -> None:
for cmd in chain(REPL._BUILTINS, REPL._COMMANDS):
result = cmd._is_consistent():
if result.is_err():
raise CmdDeclarationError(result.message)
self._history_file = history_file
readline.read_history_file(self._history_file)
def __del__(self) -> None:
readline.write_history_file(self._history_file)
def prompt(self) -> str:
return input(REPL._PROMPT)
'''
Parse and execute a string command
'''
def exec(self, cmd: str) -> Result[Command]:
cmd = cmd.strip().split()
if not len(cmd):
return Result.warn('No command given')