Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
python-version: ["3.11", "3.12", "3.13"]
poetry-version: ["1.1.15", "1.6.1"]
os: [macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
Expand Down
10 changes: 5 additions & 5 deletions ducklingscript/cli/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ def compile(
typer.Option(
help="The max amount of stacks allowed in your program", min=5, max=200
),
] = Configuration.config.stack_limit,
] = Configuration.config().stack_limit,
comments: Annotated[
bool, typer.Option(help="If comments should appear in the compiled file")
] = Configuration.config.include_comments,
] = Configuration.config().include_comments,
sourcemap: Annotated[
bool, typer.Option(help="If we should make a sourcemap")
] = Configuration.config.create_sourcemap,
] = Configuration.config().create_sourcemap,
):
"""
Compile a file, and output it to the given location with the given name.
"""
options = Configuration.config.to_dict()
options = Configuration.config().to_dict()
options.update({"stack_limit": stack_limit})
options.update({"include_comments": comments})
options.update({"create_sourcemap": sourcemap})
Expand All @@ -73,7 +73,7 @@ def compile(
) as progress:
progress.add_task(description="Compiling...", total=None)
compiled = compile_component.prepare_and_compile(
filename, output, compile_options
filename, output, False, compile_options
)
except DucklingScriptError as e:
error = e
Expand Down
13 changes: 6 additions & 7 deletions ducklingscript/cli/components/compile_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,17 @@ def compile_successful(self, compiled: Compiled):
)
self.print_std_out(compiled)
print("---")

def interpret_error(
self, error: QuackinterError, duckling_stacktrace: list[StackTraceNode]
):
stacktrace_error_str = "\n".join(
self.listify_stack_nodes(duckling_stacktrace)
)
stacktrace_error_str = "\n".join(self.listify_stack_nodes(duckling_stacktrace))
print("---\n[bright_red bold] -> Stacktrace[/bright_red bold]")
print(f"[red]{stacktrace_error_str}[/red]")
print(f"[bold red]{type(error).__name__}:[/bold red] {error.args[0]}")
print("---\n[bold bright_red]Run failed with an error.[/bold bright_red] ⛔")
print("---")


def print_std_out(self, obj: Compiled | DucklingScriptError):
if not isinstance(obj, (Compiled, CompilationError)):
return
Expand Down Expand Up @@ -98,8 +95,10 @@ def display_warnings(self, warnings: WarningsObject):
print(f"[{text_col}]{stack_trace}[/{text_col}]")
print(f"[{title_col}] -> Warning[/{title_col}]")
print(f"[{text_col}]{warning.error}[/{text_col}]")

def compile_success_with_warnings(self, warnings: WarningsObject, compiled: Compiled):

def compile_success_with_warnings(
self, warnings: WarningsObject, compiled: Compiled
):
self.display_warnings(warnings)
self.compile_successful(compiled)

Expand Down
7 changes: 4 additions & 3 deletions ducklingscript/cli/interpret.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def interpret(
typer.Option(
help="The max amount of stacks allowed in your program", min=5, max=200
),
] = Configuration.config.stack_limit,
] = Configuration.config().stack_limit,
delay: Annotated[
int,
typer.Option(help="How long in milliseconds to wait before we run the script."),
Expand All @@ -53,7 +53,7 @@ def interpret(
"""
with Progress() as progress:
main_task = progress.add_task("Loading config...", False, delay)
config = Configuration.config.to_dict()
config = Configuration.config().to_dict()
config["stack_limit"] = stack_limit
config["create_sourcemap"] = False

Expand Down Expand Up @@ -98,8 +98,9 @@ def on_fail_safe():
delay=delay, output=lambda output, line: print(f"-> {output}")
)

new_config = {**config, "quackinter_commands": True}
interpreter = DucklingInterpreter(
compile_options=CompileOptions(**config), quack_config=quack_config
compile_options=CompileOptions(**new_config), quack_config=quack_config
)
interpreter.on_compilation_successful(on_compilation_successful)
interpreter.on_compilation_failure(on_compilation_failure)
Expand Down
8 changes: 6 additions & 2 deletions ducklingscript/cli/utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ def load(cls):

with cls.config_file.open() as f:
new_config = yaml.safe_load(f)

if new_config is None:
cls.save()
return

cls._config = Config(**new_config)
cls.save()

@classmethod
@property
def config(cls) -> Config:
if cls._config is None:
cls.load()
Expand All @@ -42,7 +46,7 @@ def save(cls):

cls.create_dir()
with cls.config_file.open("w") as f:
yaml.dump(cls.config.to_dict(), f)
yaml.dump(cls.config().to_dict(), f)

@classmethod
def create_dir(cls):
Expand Down
36 changes: 22 additions & 14 deletions ducklingscript/compiler/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@
from .flipper_altcode import FlipperAltCode
from .flipper_altstring import FlipperAltString
from .flipper_default_string_delay import FlipperDefaultStringDelay
from .flipper_extended import FlipperExtended
from .flipper_device_id import FlipperDeviceId
from .flipper_special_keys import FlipperSpecialKeys
from .flipper_hold_release import FlipperHoldRelease
from .flipper_media import FlipperMedia
from .flipper_modifier_keys import FlipperModifierKeys
from .flipper_mouse_click import FlipperMouseClick
from .flipper_mouse_move import FlipperMouseMove
from .flipper_mouse_scroll import FlipperMouseScroll
from .flipper_string_delay import FlipperStringDelay
from .flipper_sysrq import FlipperSysrq
from .flipper_wait_for_button_press import FlipperWaitForButtonPress
Expand All @@ -47,6 +51,23 @@
from .quackinter_println import QuackinterPrintln

command_palette: list[type[BaseCommand]] = [
QuackinterPrintln,
QuackinterGeneralKey,
FlipperAltChar,
FlipperAltCode,
FlipperAltString,
FlipperDefaultStringDelay,
FlipperDeviceId,
FlipperSpecialKeys,
FlipperHoldRelease,
FlipperMedia,
FlipperModifierKeys,
FlipperMouseClick,
FlipperMouseMove,
FlipperMouseScroll,
FlipperStringDelay,
FlipperSysrq,
FlipperWaitForButtonPress,
Alt,
ArrowKeys,
BreakLoop,
Expand Down Expand Up @@ -75,17 +96,4 @@
Var,
While,
Whitespace,
FlipperAltChar,
FlipperAltCode,
FlipperAltString,
FlipperDefaultStringDelay,
FlipperExtended,
FlipperHoldRelease,
FlipperMedia,
FlipperModifierKeys,
FlipperStringDelay,
FlipperSysrq,
FlipperWaitForButtonPress,
QuackinterPrintln,
QuackinterGeneralKey,
]
22 changes: 19 additions & 3 deletions ducklingscript/compiler/commands/bases/base_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class BaseCommand(DocCommand):
The base for all command types
in DucklingScript.
"""

names: list[str] = []
"""
Command names to match up with this command.
Expand All @@ -32,9 +33,22 @@ def __init__(self, env: Environment, stack: Any):
self.env = env
self.stack: Stack = stack

@classmethod
def is_this_command(
cls,
self,
command_name: PreLine,
argument: str | None,
code_block: list[PreLine] | None,
stack: Any | None = None,
) -> bool:
try:
self.check_validity()
except InvalidCommandError:
return False

return self.run_is_this_command(command_name, argument, code_block, stack)

def run_is_this_command(
self,
command_name: PreLine,
argument: str | None,
code_block: list[PreLine] | None,
Expand All @@ -46,7 +60,9 @@ def is_this_command(
to override this command; instead, set
the `names` variable for this class.
"""
return False if not cls.names else (command_name.content_as_upper() in cls.names)
return (
False if not self.names else (command_name.content_as_upper() in self.names)
)

def compile(
self,
Expand Down
14 changes: 7 additions & 7 deletions ducklingscript/compiler/commands/bases/block_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ class BlockCommand(BaseCommand):
"""
Block Commands are commands that come
with a block scope after the command.

Block command example:
```
REPEAT 5
STRINGLN hello world
STRINGLN goodbye world
```
"""

accept_new_lines = True

"""
Expand Down Expand Up @@ -65,9 +66,8 @@ def token_arg(self) -> token_return_types:
raise TypeError("Argument was tokenized before it was created.")
return Tokenizer.tokenize(self.arg, self.stack, self.env)

@classmethod
def is_this_command(
cls,
def run_is_this_command(
self,
command_name: PreLine,
argument: str | None,
code_block: list[PreLine] | None,
Expand All @@ -84,10 +84,10 @@ def is_this_command(
"""
if (
command_name.content.startswith("$")
and command_name.content_as_upper()[1:] in cls.names
) or (cls.code_block_required and not code_block):
and command_name.content_as_upper()[1:] in self.names
) or (self.code_block_required and not code_block):
return False
return super().is_this_command(command_name, argument, code_block)
return super().run_is_this_command(command_name, argument, code_block)

def compile(
self,
Expand Down
1 change: 1 addition & 0 deletions ducklingscript/compiler/commands/bases/doc_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class DocCommand(ABC):
A class for making Documentation
inside of commands.
"""

description: str = ""
"""
Description of this command
Expand Down
16 changes: 8 additions & 8 deletions ducklingscript/compiler/commands/bases/simple_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,20 @@ def __iter__(self) -> Iterator[ArgLine]:
class SimpleCommand(BaseCommand):
"""
For commands that are simple. Simple commands
are all commands that don't have/require a
block scope. All Ducky Script 1.0 commands
are all commands that don't have/require a
block scope. All Ducky Script 1.0 commands
are Simple Commands.

Simple Commands support $'s and tabbed
Simple Commands support $'s and tabbed
new lines for repeating the command.

Simple Command Example:
```
STRINGLN
STRINGLN
hello world
```
"""

arg_req: ArgReqType = ArgReqType.ALLOWED
"""
If the argument should be
Expand All @@ -127,9 +128,8 @@ class SimpleCommand(BaseCommand):
"""
arg_type: type[token_return_types] | str = str

@classmethod
def is_this_command(
cls,
def run_is_this_command(
self,
command_name: PreLine,
argument: str | None,
code_block: list[PreLine] | None,
Expand All @@ -147,7 +147,7 @@ def is_this_command(
command = command_name.content_as_upper()
if command.startswith("$"):
command = command[1:]
return super().is_this_command(
return super().run_is_this_command(
PreLine(command, command_name.number, command_name.file_index),
argument,
code_block,
Expand Down
31 changes: 31 additions & 0 deletions ducklingscript/compiler/commands/flipper_device_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from .bases.doc_command import ArgReqType
from ducklingscript.compiler.commands.bases.simple_command import ArgLine
from .bases.simple_command import SimpleCommand

import re

desc = """
Set the device ID of the flipper
"""


class FlipperDeviceId(SimpleCommand):
names = ["ID"]
flipper_only = True
description = desc
arg_req = ArgReqType.REQUIRED

def verify_arg(self, arg: ArgLine) -> str | None:
content: str = arg.content
arg_parts: list[str] = content.split(" ", 1)

first_matchable = re.match(r"^[\w\d]+:[\w\d]+$", arg_parts[0])
if first_matchable is None:
return "For the first argument, you must do: VID:PID"

if len(arg_parts) == 1:
return None

second_matchable = re.match(r"^[\w\d\s]+:[\w\d\s]+$", arg_parts[1])
if second_matchable is None:
return "The second argument is OPTIONAL, but must be: Manufacturer:Product"
Loading
Loading