├── tests ├── __init__.py ├── compiler │ └── __init__.py ├── decompiler │ └── __init__.py └── fixtures │ └── compiler │ └── macros_imports_test │ ├── test_err_notfound │ └── main.exps │ ├── test_complex │ ├── other_file2.exps │ ├── other_file.exps │ └── main.exps │ ├── test_other_file │ ├── other_file.exps │ └── main.exps │ ├── test_other_two │ ├── other_file2.exps │ ├── other_file.exps │ └── main.exps │ ├── test_simple1 │ └── main.exps │ ├── test_simple2 │ └── main.exps │ ├── test_err_params │ └── main.exps │ ├── test_err_recursion1 │ └── main.exps │ ├── test_err_recursion2 │ └── main.exps │ ├── test_nested │ └── main.exps │ ├── test_simple3_chain │ └── main.exps │ └── test_nested_chain │ └── main.exps ├── explorerscript ├── py.typed ├── ssb_script │ ├── README.rst │ ├── __init__.py │ └── ssb_converting │ │ ├── __init__.py │ │ └── compiler │ │ └── __init__.py ├── pygments │ └── __init__.py ├── ssb_converting │ ├── __init__.py │ ├── compiler │ │ ├── __init__.py │ │ ├── compile_handlers │ │ │ ├── __init__.py │ │ │ ├── atoms │ │ │ │ ├── __init__.py │ │ │ │ ├── position_marker_arg.py │ │ │ │ ├── label.py │ │ │ │ ├── assignment_operator.py │ │ │ │ ├── scn_var.py │ │ │ │ ├── value_of.py │ │ │ │ ├── conditional_operator.py │ │ │ │ └── position_marker.py │ │ │ ├── blocks │ │ │ │ ├── __init__.py │ │ │ │ ├── ctxs │ │ │ │ │ └── __init__.py │ │ │ │ ├── ifs │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── header │ │ │ │ │ │ ├── __init__.py │ │ │ │ │ │ └── negatable.py │ │ │ │ │ └── else_block.py │ │ │ │ ├── loop │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── forever_block.py │ │ │ │ └── switches │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── case_headers │ │ │ │ │ └── __init__.py │ │ │ │ │ └── switch_headers │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── sector.py │ │ │ │ │ ├── random.py │ │ │ │ │ ├── dungeon_mode.py │ │ │ │ │ └── scn.py │ │ │ ├── assignments │ │ │ │ ├── __init__.py │ │ │ │ ├── assignment_clear.py │ │ │ │ ├── assignment_initial.py │ │ │ │ ├── assignment_adventure_log.py │ │ │ │ ├── assignment_scenario.py │ │ │ │ ├── assignment_reset.py │ │ │ │ └── assignment_dungeon_mode.py │ │ │ ├── functions │ │ │ │ ├── __init__.py │ │ │ │ ├── coro_def.py │ │ │ │ ├── simple_def.py │ │ │ │ └── macro_def.py │ │ │ ├── operations │ │ │ │ ├── __init__.py │ │ │ │ ├── arg.py │ │ │ │ ├── arg_list.py │ │ │ │ └── macro_call.py │ │ │ ├── statements │ │ │ │ ├── __init__.py │ │ │ │ ├── call.py │ │ │ │ ├── jump.py │ │ │ │ └── control_statement.py │ │ │ └── null.py │ │ ├── compiler_visitor │ │ │ ├── __init__.py │ │ │ ├── has_routines_visitor.py │ │ │ └── import_visitor.py │ │ ├── meta_attributes.py │ │ └── label_jump_to_remover.py │ ├── decompiler │ │ ├── __init__.py │ │ ├── graph_building │ │ │ └── __init__.py │ │ ├── write_handlers │ │ │ ├── __init__.py │ │ │ ├── labels │ │ │ │ └── __init__.py │ │ │ ├── label_jumps │ │ │ │ ├── __init__.py │ │ │ │ ├── call.py │ │ │ │ ├── jump.py │ │ │ │ ├── forever_continue.py │ │ │ │ └── forever_break.py │ │ │ ├── simple_ops │ │ │ │ ├── __init__.py │ │ │ │ └── keyword.py │ │ │ ├── abstract.py │ │ │ └── foreign_label.py │ │ └── write_handler_manager.py │ └── util.py ├── __init__.py ├── error.py ├── explorerscript_reader.py ├── cli │ └── __init__.py ├── syntax_error_listener.py └── util.py ├── explorerscript_parser ├── py.typed ├── SsbScriptVisitor.cpp ├── SsbScriptBaseVisitor.cpp ├── ExplorerScriptVisitor.cpp ├── ExplorerScriptBaseVisitor.cpp ├── parser_wrapper_ssbs.h ├── parser_wrapper_exps.h ├── SsbScript.tokens ├── SsbScriptLexer.tokens ├── parser_wrapper_ssbs.cpp ├── parser_wrapper_exps.cpp ├── SsbScript.g4 ├── SsbScriptLexer.h ├── SsbScriptVisitor.h ├── ExplorerScriptLexer.h ├── ExplorerScript.tokens └── ExplorerScriptLexer.tokens ├── requirements-docs.txt ├── setup.py ├── docs ├── requirements.txt └── index.rst ├── .gitmodules ├── requirements.txt ├── mypy.ini ├── tox.ini ├── riptide.yml ├── MANIFEST.in ├── .github ├── dependabot.yml └── ISSUE_TEMPLATE │ └── language-feature-idea.md ├── example ├── macros │ └── dir │ │ ├── macros2.exps │ │ └── macros1.exps ├── SCRIPT │ └── base.exps └── example_compile.py ├── .readthedocs.yaml ├── .vscode ├── c_cpp_properties.json └── settings.json ├── LICENSE ├── README.rst ├── CMakeLists.txt ├── .gitignore ├── pyproject.toml └── Makefile /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /explorerscript/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/compiler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/decompiler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /explorerscript_parser/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements-docs.txt: -------------------------------------------------------------------------------- 1 | pygments==2.19.1 2 | .[pygments] 3 | furo -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(cmake_source_dir=".") 4 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | furo 2 | . # rtd reads this from one directory down, so "." is the project itself -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "antlr4"] 2 | path = antlr4 3 | url = https://github.com/SkyTemple/antlr4 4 | branch = skytemple-fork 5 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_err_notfound/main.exps: -------------------------------------------------------------------------------- 1 | def 0 { 2 | ~test_macro("Hello World", 123); 3 | } 4 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_complex/other_file2.exps: -------------------------------------------------------------------------------- 1 | macro other_macro2($var1) { 2 | doSomething($var1); 3 | } -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_other_file/other_file.exps: -------------------------------------------------------------------------------- 1 | macro other_macro($var1) { 2 | doSomething($var1); 3 | } -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_other_two/other_file2.exps: -------------------------------------------------------------------------------- 1 | macro other_macro2($var1) { 2 | doSomething($var1); 3 | } -------------------------------------------------------------------------------- /explorerscript_parser/SsbScriptVisitor.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Generated from SsbScript.g4 by ANTLR 4.13.0 3 | 4 | 5 | #include "SsbScriptVisitor.h" 6 | 7 | 8 | -------------------------------------------------------------------------------- /explorerscript_parser/SsbScriptBaseVisitor.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Generated from SsbScript.g4 by ANTLR 4.13.0 3 | 4 | 5 | #include "SsbScriptBaseVisitor.h" 6 | 7 | 8 | -------------------------------------------------------------------------------- /explorerscript_parser/ExplorerScriptVisitor.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Generated from ExplorerScript.g4 by ANTLR 4.13.0 3 | 4 | 5 | #include "ExplorerScriptVisitor.h" 6 | 7 | 8 | -------------------------------------------------------------------------------- /explorerscript_parser/ExplorerScriptBaseVisitor.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Generated from ExplorerScript.g4 by ANTLR 4.13.0 3 | 4 | 5 | #include "ExplorerScriptBaseVisitor.h" 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_other_two/other_file.exps: -------------------------------------------------------------------------------- 1 | import "./other_file2.exps"; 2 | 3 | macro other_macro($var1) { 4 | doSomething($var1); 5 | ~other_macro2($var1); 6 | } -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_simple1/main.exps: -------------------------------------------------------------------------------- 1 | def 0 { 2 | ~test_macro("Hello World", 123); 3 | } 4 | 5 | macro test_macro($var1, $var2) { 6 | doSomething($var1, $var2); 7 | } -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_simple2/main.exps: -------------------------------------------------------------------------------- 1 | macro test_macro($var1, $var2) { 2 | doSomething($var1, $var2); 3 | } 4 | 5 | def 0 { 6 | ~test_macro("Hello World", 123); 7 | } -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_err_params/main.exps: -------------------------------------------------------------------------------- 1 | def 0 { 2 | ~test_macro("Hello World"); 3 | } 4 | 5 | macro test_macro($var1, $var2) { 6 | doSomething($var1, $var2); 7 | } 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scikit-build-core==0.10.7 2 | igraph==0.11.8 3 | pygments>=2.6.1 4 | types-Pygments 5 | skytemple-3rdparty-typestubs==1.1.1 6 | ruff 7 | mypy 8 | typing_extensions >= 4.0; python_version < "3.11" 9 | pybind11==2.13.6 -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_err_recursion1/main.exps: -------------------------------------------------------------------------------- 1 | def 0 { 2 | ~test_macro("Hello World"); 3 | } 4 | 5 | macro test_macro($var1, $var2) { 6 | doSomething($var1, $var2); 7 | ~test_macro($var1, $var2); 8 | } 9 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | warn_unused_configs = True 3 | mypy_path = . 4 | explicit_package_bases = True 5 | namespace_packages = True 6 | check_untyped_defs = True 7 | allow_untyped_defs = False 8 | allow_any_generics = False 9 | exclude = antlr4 10 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. title:: ExplorerScript 2 | 3 | .. include:: ../README.rst 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | language_spec 9 | cli_api_usage 10 | source_maps 11 | 12 | * :ref:`genindex` 13 | * :ref:`modindex` 14 | * :ref:`search` 15 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_other_file/main.exps: -------------------------------------------------------------------------------- 1 | import "./other_file.exps"; 2 | 3 | def 0 { 4 | ~test_macro("Hello World", 123); 5 | ~other_macro("In other file"); 6 | } 7 | 8 | macro test_macro($var1, $var2) { 9 | doSomething($var1, $var2); 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_err_recursion2/main.exps: -------------------------------------------------------------------------------- 1 | def 0 { 2 | ~test_macro("Hello World"); 3 | } 4 | 5 | macro test_macro($var1, $var2) { 6 | doSomething($var1, $var2); 7 | ~recurse($var1, $var2); 8 | } 9 | 10 | macro recurse($var1, $var2) { 11 | ~test_macro($var1, $var2); 12 | } 13 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py310,py311,py312,py313 3 | skipsdist = {env:TOXBUILD:false} 4 | 5 | [gh-actions] 6 | python = 7 | 3.10: py310 8 | 3.11: py311 9 | 3.12: py312 10 | 3.13: py313 11 | 12 | [testenv] 13 | commands = 14 | pytest --junitxml pytest.xml {posargs} 15 | deps = 16 | -r requirements.txt 17 | pytest 18 | -------------------------------------------------------------------------------- /riptide.yml: -------------------------------------------------------------------------------- 1 | project: 2 | name: explorerscript-docs 3 | src: . 4 | app: 5 | $ref: /app/sphinx/latest 6 | services: 7 | sphinx: 8 | environment: 9 | REQUIREMENTS_FILE: "requirements-docs.txt" 10 | SPHINX_SOURCE: docs 11 | SPHINX_BUILD: docs/build 12 | commands: 13 | make: $remove -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include explorerscript/py.typed 2 | include explorerscript_parser/py.typed 3 | recursive-include explorerscript_parser *.pyi 4 | recursive-include explorerscript_parser *.cpp 5 | recursive-include explorerscript_parser *.h 6 | recursive-include explorerscript_parser *.g4 7 | include CMakeLists.txt 8 | include ExternalAntlr4Cpp.cmake 9 | graft antlr4 -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_other_two/main.exps: -------------------------------------------------------------------------------- 1 | import "./other_file.exps"; 2 | import "./other_file2.exps"; 3 | 4 | def 0 { 5 | ~test_macro("Hello World", 123); 6 | ~other_macro("In other file"); 7 | ~other_macro2("In other file"); 8 | } 9 | 10 | macro test_macro($var1, $var2) { 11 | doSomething($var1, $var2); 12 | } 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | reviewers: 8 | - "skytemple/dependabot-reviewers" 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | reviewers: 14 | - "skytemple/dependabot-reviewers" 15 | -------------------------------------------------------------------------------- /example/macros/dir/macros2.exps: -------------------------------------------------------------------------------- 1 | macro macro_in_macros_2() { 2 | debug_Print("macro_in_macros_2"); 3 | // If the op above would be removed, we couldn't accurately create the jump source map entry for calls to 4 | // macro_in_macros_2, but that's just how it is, since macro calls don't create mappable operations. 5 | ~macro2_in_macros_2(); 6 | NUMBER_ONE_im_in_macros_2(); 7 | } 8 | macro macro2_in_macros_2() { 9 | NUMBER_TWO_im_in_macros_2(); 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_complex/other_file.exps: -------------------------------------------------------------------------------- 1 | import "./other_file2.exps"; 2 | 3 | macro other_macro($var1) { 4 | doSomething($var1); 5 | ~other_macro2($var1); 6 | } 7 | 8 | macro other_macro_caller($var1) { 9 | ~other_macro($var1); 10 | ~other_macro_bottom($var1); 11 | ~other_macro($var1); 12 | ~other_macro_bottom($var1); 13 | } 14 | 15 | macro other_macro_bottom($var1) { 16 | doSomething($var1); 17 | ~other_macro2($var1); 18 | ~other_macro($var1); 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_nested/main.exps: -------------------------------------------------------------------------------- 1 | macro test_macro($var1, $var2) { 2 | doSomething($var1, $var2); 3 | } 4 | 5 | macro test_macro2($var1, $var2) { 6 | doSomething($var1, $var2); 7 | ~test_macro3("Hello World", 123); 8 | } 9 | 10 | def 0 { 11 | ~test_macro("Hello World", 123); 12 | ~test_macro2("Hello World", 123); 13 | ~test_macro3("Hello World", 123); 14 | } 15 | 16 | macro test_macro3($var1, $var2) { 17 | doSomething($var1, $var2); 18 | ~test_macro("Hello World", 123); 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_simple3_chain/main.exps: -------------------------------------------------------------------------------- 1 | macro test_macro4($var1, $var2) { 2 | doSomething($var1, $var2); 3 | } 4 | 5 | macro test_macro($var1, $var2) { 6 | doSomething($var1, $var2); 7 | ~test_macro2("Hello World", 123); 8 | } 9 | 10 | def 0 { 11 | ~test_macro("Hello World", 123); 12 | } 13 | 14 | macro test_macro2($var1, $var2) { 15 | doSomething($var1, $var2); 16 | ~test_macro3("Hello World", 123); 17 | } 18 | 19 | macro test_macro3($var1, $var2) { 20 | doSomething($var1, $var2); 21 | ~test_macro4("Hello World", 123); 22 | } -------------------------------------------------------------------------------- /explorerscript/ssb_script/README.rst: -------------------------------------------------------------------------------- 1 | SSBScript 2 | ========= 3 | SSBScript is a "variant" of ExplorerScript, which 4 | is nearer to the original SSB binary format and thus 5 | easier to convert into/from SSB binaries. 6 | 7 | It is almost a subscript of ExplorerScript, but it has 8 | special syntax for jumps not present in ExplorerScript. 9 | Other than that it only supports the general 10 | routine statements and regular operation 11 | statements, even for statements that have special 12 | syntax in ExplorerScript. 13 | 14 | It is meant to be direct representation of a binaries SSB opcodes. 15 | -------------------------------------------------------------------------------- /example/SCRIPT/base.exps: -------------------------------------------------------------------------------- 1 | import "dir/macros1.exps"; 2 | 3 | macro local_macro(%i1, %i2, %i3, %aString) { 4 | debug_Print("Begin LocalMacro"); 5 | vars(%i1, %i2, %i3, %aString); 6 | ~remote_macro(%i2, %aString); 7 | debug_Print("End LocalMacro"); 8 | } 9 | 10 | def 0 { 11 | debug_Print("Before Macro"); 12 | ~local_macro(Position<'PositionName', 10, 10.5>, 2, 3, "String"); 13 | ~local_macro(10, 9, 8, "Another one"); 14 | //~local_macro("not enough arguments"); 15 | debug_Print("After Macro"); 16 | } 17 | 18 | def 1 for actor TEST { 19 | test_actor(); 20 | } 21 | 22 | def 2 for actor 2 { 23 | test_actor_id(); 24 | } 25 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_complex/main.exps: -------------------------------------------------------------------------------- 1 | import "./other_file.exps"; 2 | import "./other_file2.exps"; 3 | 4 | macro test_macro2($var1, $var2) { 5 | doSomething($var1, $var2); 6 | ~other_macro_caller("In other file"); 7 | } 8 | 9 | def 0 { 10 | ~test_macro("Hello World", 123); 11 | ~other_macro_caller("In other file"); 12 | ~other_macro("In other file"); 13 | ~other_macro2("In other file"); 14 | ~test_macro2("Hello World", 123); 15 | } 16 | 17 | macro test_macro($var1, $var2) { 18 | doSomething($var1, $var2); 19 | ~test_macro2("Hello World", 123); 20 | ~other_macro_caller("In other file"); 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/compiler/macros_imports_test/test_nested_chain/main.exps: -------------------------------------------------------------------------------- 1 | macro test_macro($var1, $var2) { 2 | doSomething($var1, $var2); 3 | ~test_macro4("Hello World", 123); 4 | } 5 | 6 | macro test_macro2($var1, $var2) { 7 | doSomething($var1, $var2); 8 | ~test_macro("Hello World", 123); 9 | } 10 | 11 | def 0 { 12 | ~test_macro("Hello World", 123); 13 | ~test_macro2("Hello World", 123); 14 | ~test_macro3("Hello World", 123); 15 | } 16 | 17 | macro test_macro3($var1, $var2) { 18 | doSomething($var1, $var2); 19 | ~test_macro("Hello World", 123); 20 | ~test_macro2("Hello World", 123); 21 | } 22 | 23 | 24 | macro test_macro4($var1, $var2) { 25 | doSomething($var1, $var2); 26 | } 27 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.12" 12 | 13 | # Build documentation in the "docs/" directory with Sphinx 14 | sphinx: 15 | configuration: docs/conf.py 16 | 17 | 18 | # Optional but recommended, declare the Python requirements required 19 | # to build your documentation 20 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 21 | python: 22 | install: 23 | - requirements: docs/requirements.txt 24 | 25 | submodules: 26 | include: all 27 | -------------------------------------------------------------------------------- /explorerscript_parser/parser_wrapper_ssbs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "antlr4-runtime.h" 4 | #include "SsbScriptLexer.h" 5 | #include "SsbScriptParser.h" 6 | #include "SsbScriptBaseVisitor.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class SsbScriptParserWrapper { 13 | antlr4::ANTLRInputStream* input; 14 | SsbScriptLexer* lexer; 15 | antlr4::CommonTokenStream* tokens; 16 | SsbScriptParser* parser; 17 | SsbScriptParser::StartContext* tree; 18 | public: 19 | SsbScriptParserWrapper(std::string& string, antlr4::ANTLRErrorListener* listener); 20 | ~SsbScriptParserWrapper(); 21 | 22 | SsbScriptParser::StartContext* getTree(); 23 | pybind11::object traverse(SsbScriptBaseVisitor& visitor); 24 | }; 25 | -------------------------------------------------------------------------------- /explorerscript_parser/parser_wrapper_exps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "antlr4-runtime.h" 4 | #include "ExplorerScriptLexer.h" 5 | #include "ExplorerScriptParser.h" 6 | #include "ExplorerScriptBaseVisitor.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class ExplorerScriptParserWrapper { 13 | antlr4::ANTLRInputStream* input; 14 | ExplorerScriptLexer* lexer; 15 | antlr4::CommonTokenStream* tokens; 16 | ExplorerScriptParser* parser; 17 | ExplorerScriptParser::StartContext* tree; 18 | public: 19 | ExplorerScriptParserWrapper(std::string& string, antlr4::ANTLRErrorListener* listener); 20 | ~ExplorerScriptParserWrapper(); 21 | 22 | ExplorerScriptParser::StartContext* getTree(); 23 | pybind11::object traverse(ExplorerScriptBaseVisitor& visitor); 24 | }; 25 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/opt/homebrew/include", 8 | "/opt/homebrew/include/antlr4-runtime", 9 | "/opt/homebrew/include/pybind11", 10 | "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Headers" 11 | ], 12 | "defines": [], 13 | "macFrameworkPath": [ 14 | "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/System/Library/Frameworks" 15 | ], 16 | "compilerPath": "/opt/homebrew/opt/llvm/bin/clang", 17 | "cStandard": "c17", 18 | "cppStandard": "c++17", 19 | "intelliSenseMode": "macos-clang-arm64" 20 | } 21 | ], 22 | "version": 4 23 | } -------------------------------------------------------------------------------- /explorerscript_parser/SsbScript.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | STRING_LITERAL=2 3 | MULTILINE_STRING_LITERAL=3 4 | FOR_TARGET=4 5 | CORO=5 6 | DEF=6 7 | FOR_ACTOR=7 8 | FOR_OBJECT=8 9 | FOR_PERFORMER=9 10 | ALIAS=10 11 | FOR=11 12 | PREVIOUS=12 13 | POSITION=13 14 | IDENTIFIER=14 15 | VARIABLE=15 16 | MACRO_CALL=16 17 | INTEGER=17 18 | DECIMAL_INTEGER=18 19 | OCT_INTEGER=19 20 | HEX_INTEGER=20 21 | BIN_INTEGER=21 22 | OPEN_PAREN=22 23 | CLOSE_PAREN=23 24 | COMMA=24 25 | COLON=25 26 | ASSIGN=26 27 | PLUS=27 28 | AT=28 29 | PARAGRAPH=29 30 | OPEN_BRACE=30 31 | CLOSE_BRACE=31 32 | OPEN_SHARP=32 33 | CLOSE_SHARP=33 34 | DECIMAL=34 35 | SKIP_=35 36 | UNKNOWN_CHAR=36 37 | ';'=1 38 | 'coro'=5 39 | 'def'=6 40 | 'for_actor'=7 41 | 'for_object'=8 42 | 'for_performer'=9 43 | 'alias'=10 44 | 'for'=11 45 | 'previous'=12 46 | 'Position'=13 47 | '('=22 48 | ')'=23 49 | ','=24 50 | ':'=25 51 | '='=26 52 | '+'=27 53 | '@'=28 54 | '§'=29 55 | '{'=30 56 | '}'=31 57 | '<'=32 58 | '>'=33 59 | -------------------------------------------------------------------------------- /explorerscript_parser/SsbScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | STRING_LITERAL=2 3 | MULTILINE_STRING_LITERAL=3 4 | FOR_TARGET=4 5 | CORO=5 6 | DEF=6 7 | FOR_ACTOR=7 8 | FOR_OBJECT=8 9 | FOR_PERFORMER=9 10 | ALIAS=10 11 | FOR=11 12 | PREVIOUS=12 13 | POSITION=13 14 | IDENTIFIER=14 15 | VARIABLE=15 16 | MACRO_CALL=16 17 | INTEGER=17 18 | DECIMAL_INTEGER=18 19 | OCT_INTEGER=19 20 | HEX_INTEGER=20 21 | BIN_INTEGER=21 22 | OPEN_PAREN=22 23 | CLOSE_PAREN=23 24 | COMMA=24 25 | COLON=25 26 | ASSIGN=26 27 | PLUS=27 28 | AT=28 29 | PARAGRAPH=29 30 | OPEN_BRACE=30 31 | CLOSE_BRACE=31 32 | OPEN_SHARP=32 33 | CLOSE_SHARP=33 34 | DECIMAL=34 35 | SKIP_=35 36 | UNKNOWN_CHAR=36 37 | ';'=1 38 | 'coro'=5 39 | 'def'=6 40 | 'for_actor'=7 41 | 'for_object'=8 42 | 'for_performer'=9 43 | 'alias'=10 44 | 'for'=11 45 | 'previous'=12 46 | 'Position'=13 47 | '('=22 48 | ')'=23 49 | ','=24 50 | ':'=25 51 | '='=26 52 | '+'=27 53 | '@'=28 54 | '§'=29 55 | '{'=30 56 | '}'=31 57 | '<'=32 58 | '>'=33 59 | -------------------------------------------------------------------------------- /example/macros/dir/macros1.exps: -------------------------------------------------------------------------------- 1 | import "./macros2.exps"; 2 | 3 | macro remote_macro(%aVariable, %aString) { 4 | vars_in_remote_macro(%aVariable, %aString, $notAvailable); 5 | ~remote_macro2("from remote_macro", %aString); 6 | debug_Print("REMOTE2 SHOULD END HERE"); 7 | ~macro_in_macros_2(); 8 | } 9 | 10 | macro remote_macro2(%aString, %anotherString) { 11 | debug_Print("BELOW IS A TEST RETURN"); 12 | if ($TEST_VAR < 3) { 13 | print("The variable is smaller"); 14 | return; // This should jump out of the macro. 15 | } 16 | vars_in_remote_macro2(%aString, %anotherString, $notAvailable); 17 | } 18 | 19 | /*macro calls_local_macro($i1, $i2, $i3, %aString) { 20 | // Compiling this must fail, because local_macro is in base. 21 | ~local_macro($i1, $i2, $i3, %aString); 22 | }*/ 23 | 24 | /*macro recursion2() { 25 | // Compiling this must fail, because of the dependency cycle 26 | ~recursion(); 27 | } 28 | 29 | macro recursion() { 30 | ~recursion2(); 31 | }*/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Parakoopa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /explorerscript_parser/parser_wrapper_ssbs.cpp: -------------------------------------------------------------------------------- 1 | #include "parser_wrapper_ssbs.h" 2 | 3 | using namespace std; 4 | using namespace antlr4; 5 | 6 | SsbScriptParserWrapper::SsbScriptParserWrapper(std::string& string, ANTLRErrorListener* listener) { 7 | this->input = new ANTLRInputStream(string); 8 | this->lexer = new SsbScriptLexer(input); 9 | this->tokens = new CommonTokenStream(lexer); 10 | this->parser = new SsbScriptParser(tokens); 11 | this->parser->getInterpreter()->setPredictionMode(antlr4::atn::PredictionMode::SLL); 12 | this->parser->removeErrorListeners(); 13 | this->parser->addErrorListener(listener); 14 | this->tree = this->parser->start(); 15 | } 16 | 17 | SsbScriptParserWrapper::~SsbScriptParserWrapper() { 18 | delete this->parser; 19 | delete this->tokens; 20 | delete this->lexer; 21 | delete this->input; 22 | } 23 | 24 | SsbScriptParser::StartContext* SsbScriptParserWrapper::getTree() { 25 | return this->tree; 26 | } 27 | 28 | pybind11::object SsbScriptParserWrapper::traverse(SsbScriptBaseVisitor& visitor) { 29 | auto ret = this->tree->accept(&visitor); 30 | return std::any_cast(ret); 31 | } 32 | -------------------------------------------------------------------------------- /explorerscript_parser/parser_wrapper_exps.cpp: -------------------------------------------------------------------------------- 1 | #include "parser_wrapper_exps.h" 2 | 3 | using namespace std; 4 | using namespace antlr4; 5 | 6 | ExplorerScriptParserWrapper::ExplorerScriptParserWrapper(std::string& string, ANTLRErrorListener* listener) { 7 | this->input = new ANTLRInputStream(string); 8 | this->lexer = new ExplorerScriptLexer(input); 9 | this->tokens = new CommonTokenStream(lexer); 10 | this->parser = new ExplorerScriptParser(tokens); 11 | this->parser->getInterpreter()->setPredictionMode(antlr4::atn::PredictionMode::SLL); 12 | this->parser->removeErrorListeners(); 13 | this->parser->addErrorListener(listener); 14 | this->tree = this->parser->start(); 15 | } 16 | 17 | ExplorerScriptParserWrapper::~ExplorerScriptParserWrapper() { 18 | delete this->parser; 19 | delete this->tokens; 20 | delete this->lexer; 21 | delete this->input; 22 | } 23 | 24 | ExplorerScriptParser::StartContext* ExplorerScriptParserWrapper::getTree() { 25 | return this->tree; 26 | } 27 | 28 | pybind11::object ExplorerScriptParserWrapper::traverse(ExplorerScriptBaseVisitor& visitor) { 29 | auto ret = this->tree->accept(&visitor); 30 | return std::any_cast(ret); 31 | } 32 | -------------------------------------------------------------------------------- /explorerscript/pygments/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_script/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_script/ssb_converting/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_script/ssb_converting/compiler/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | EXPLORERSCRIPT_EXT = ".exps" 26 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compiler_visitor/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/graph_building/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/labels/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/ctxs/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/ifs/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/loop/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/functions/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/operations/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/statements/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/label_jumps/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/simple_ops/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/ifs/header/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/case_headers/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/switch_headers/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "__bit_reference": "cpp", 4 | "__config": "cpp", 5 | "__locale": "cpp", 6 | "__threading_support": "cpp", 7 | "__verbose_abort": "cpp", 8 | "array": "cpp", 9 | "bitset": "cpp", 10 | "cctype": "cpp", 11 | "charconv": "cpp", 12 | "clocale": "cpp", 13 | "cmath": "cpp", 14 | "cstdarg": "cpp", 15 | "cstddef": "cpp", 16 | "cstdint": "cpp", 17 | "cstdio": "cpp", 18 | "cstdlib": "cpp", 19 | "cstring": "cpp", 20 | "ctime": "cpp", 21 | "cwchar": "cpp", 22 | "cwctype": "cpp", 23 | "forward_list": "cpp", 24 | "fstream": "cpp", 25 | "initializer_list": "cpp", 26 | "iomanip": "cpp", 27 | "ios": "cpp", 28 | "iosfwd": "cpp", 29 | "iostream": "cpp", 30 | "istream": "cpp", 31 | "limits": "cpp", 32 | "locale": "cpp", 33 | "mutex": "cpp", 34 | "new": "cpp", 35 | "ostream": "cpp", 36 | "print": "cpp", 37 | "ratio": "cpp", 38 | "sstream": "cpp", 39 | "stdexcept": "cpp", 40 | "streambuf": "cpp", 41 | "string": "cpp", 42 | "string_view": "cpp", 43 | "tuple": "cpp", 44 | "typeinfo": "cpp", 45 | "algorithm": "cpp", 46 | "memory": "cpp", 47 | "chrono": "cpp", 48 | "valarray": "cpp" 49 | } 50 | } -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ExplorerScript 2 | ============== 3 | 4 | |build| |docs| |pypi-version| |pypi-downloads| |pypi-license| |pypi-pyversions| |discord| 5 | 6 | .. |build| image:: https://img.shields.io/github/actions/workflow/status/SkyTemple/ExplorerScript/build-test-publish.yml 7 | :target: https://pypi.org/project/explorerscript/ 8 | :alt: Build Status 9 | 10 | .. |docs| image:: https://readthedocs.org/projects/explorerscript/badge/?version=latest 11 | :target: https://explorerscript.readthedocs.io/en/latest/?badge=latest 12 | :alt: Documentation Status 13 | 14 | .. |pypi-version| image:: https://img.shields.io/pypi/v/explorerscript 15 | :target: https://pypi.org/project/explorerscript/ 16 | :alt: Version 17 | 18 | .. |pypi-downloads| image:: https://img.shields.io/pypi/dm/explorerscript 19 | :target: https://pypi.org/project/explorerscript/ 20 | :alt: Downloads 21 | 22 | .. |pypi-license| image:: https://img.shields.io/pypi/l/explorerscript 23 | :alt: License (GPLv3) 24 | 25 | .. |pypi-pyversions| image:: https://img.shields.io/pypi/pyversions/explorerscript 26 | :alt: Supported Python versions 27 | 28 | .. |discord| image:: https://img.shields.io/discord/710190644152369162?label=Discord 29 | :target: https://discord.gg/skytemple 30 | :alt: Discord 31 | 32 | A programming language + compiler/decompiler for creating scripts for Pokémon Mystery 33 | Dungeon Explorers of Sky. 34 | 35 | Documentation can be found at https://explorerscript.readthedocs.org (or in the docs directory). 36 | -------------------------------------------------------------------------------- /explorerscript_parser/SsbScript.g4: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2020-2024 Capypara and the SkyTemple contributors 5 | * 6 | * Permission is hereby granted, free of charge, to any person 7 | * obtaining a copy of this software and associated documentation 8 | * files (the "Software"), to deal in the Software without 9 | * restriction, including without limitation the rights to use, 10 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following 13 | * conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | * OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | grammar SsbScript; 28 | import SsbCommon; 29 | 30 | /* 31 | * parser rules 32 | */ 33 | 34 | pos_argument: primitive | position_marker | jump_marker; 35 | 36 | jump_marker: AT IDENTIFIER; 37 | 38 | /* 39 | * lexer rules 40 | */ 41 | 42 | // No specific rules. 43 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15...3.29) 2 | project(explorerscript LANGUAGES CXX) 3 | 4 | set(CMAKE_POSITION_INDEPENDENT_CODE "ON") 5 | 6 | if(APPLE) 7 | execute_process( 8 | COMMAND brew --prefix llvm 9 | OUTPUT_VARIABLE HOMEBREW_LLVM_PREFIX 10 | OUTPUT_STRIP_TRAILING_WHITESPACE 11 | ) 12 | if(HOMEBREW_LLVM_PREFIX) 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${HOMEBREW_LLVM_PREFIX}/lib/c++ -stdlib=libc++") 14 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${HOMEBREW_LLVM_PREFIX}/lib/c++ -stdlib=libc++") 15 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L${HOMEBREW_LLVM_PREFIX}/lib/c++ -stdlib=libc++") 16 | include_directories(${HOMEBREW_LLVM_PREFIX}/include) 17 | list(APPEND CMAKE_PREFIX_PATH ${HOMEBREW_LLVM_PREFIX}) 18 | else() 19 | message(WARNING "Homebrew LLVM not found. Using system default, this might or might not work.") 20 | endif() 21 | endif() 22 | 23 | if(MSVC) 24 | set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1) 25 | endif() 26 | 27 | file(GLOB plugin_src 28 | "./explorerscript_parser/*.cpp" 29 | ) 30 | 31 | set(CMAKE_CXX_STANDARD 17) 32 | set(PYBIND11_FINDPYTHON ON) 33 | find_package(pybind11 CONFIG REQUIRED) 34 | 35 | add_definitions(-DANTLR4CPP_STATIC) 36 | set(ANTLR4_WITH_STATIC_CRT OFF) 37 | include(./ExternalAntlr4Cpp.cmake) 38 | include_directories(${ANTLR4_INCLUDE_DIRS}) 39 | pybind11_add_module(explorerscript_parser ${plugin_src}) 40 | target_link_libraries(explorerscript_parser PRIVATE antlr4_static) 41 | 42 | install(TARGETS explorerscript_parser DESTINATION .) 43 | -------------------------------------------------------------------------------- /explorerscript/error.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.syntax_error_listener import AntlrSyntaxError 26 | 27 | 28 | class ParseError(Exception): 29 | """A syntax error during the parsing of SSBScript or ExplorerScript.""" 30 | 31 | def __init__(self, error: AntlrSyntaxError): 32 | self.error = error 33 | 34 | def __str__(self) -> str: 35 | return str(self.error) 36 | 37 | 38 | class SsbCompilerError(Exception): 39 | pass 40 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/null.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 26 | from explorerscript_parser import Antlr4ParserRuleContext 27 | 28 | 29 | class NullCompileHandler(AbstractCompileHandler[Antlr4ParserRuleContext, None]): 30 | def collect(self) -> None: 31 | raise AssertionError("collect called on NullCompileHandler.") 32 | 33 | def add(self, obj: None) -> None: 34 | raise AssertionError("add called on NullCompileHandler.") 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/language-feature-idea.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Language Feature Idea 3 | about: Suggest a new language feature for ExplorerScript 4 | title: '' 5 | labels: exps-language-feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Summary 11 | 12 | 13 | ### Dependencies 14 | 15 | This needs the following features to be implemented first: 16 | - #XYZ 17 | 18 | ## Motivation 19 | 20 | 21 | ## Examples 22 | 23 | 24 | ```exps 25 | def 0 { 26 | // ... 27 | } 28 | ``` 29 | A short explanation for the first example. 30 | ```exps 31 | const XYZ = 3; 32 | ``` 33 | A short explanation for the second example. 34 | 35 | ## Language Changes 36 | 37 | 38 | ### Parser and Lexer Changes 39 | 40 | 41 | ### Behaviour 42 | 43 | 44 | ## Compiler Implementation 45 | 46 | 47 | ### Compiler Interface Changes 48 | 49 | 50 | ### Decompiler Changes 51 | 52 | 53 | ## How to teach 54 | 55 | 56 | ## Alternatives 57 | 58 | 59 | ## Backwards compatibility 60 | 61 | -------------------------------------------------------------------------------- /explorerscript_parser/SsbScriptLexer.h: -------------------------------------------------------------------------------- 1 | 2 | // Generated from SsbScript.g4 by ANTLR 4.13.0 3 | 4 | #pragma once 5 | 6 | 7 | #include "antlr4-runtime.h" 8 | 9 | 10 | 11 | 12 | class SsbScriptLexer : public antlr4::Lexer { 13 | public: 14 | enum { 15 | T__0 = 1, STRING_LITERAL = 2, MULTILINE_STRING_LITERAL = 3, FOR_TARGET = 4, 16 | CORO = 5, DEF = 6, FOR_ACTOR = 7, FOR_OBJECT = 8, FOR_PERFORMER = 9, 17 | ALIAS = 10, FOR = 11, PREVIOUS = 12, POSITION = 13, IDENTIFIER = 14, 18 | VARIABLE = 15, MACRO_CALL = 16, INTEGER = 17, DECIMAL_INTEGER = 18, 19 | OCT_INTEGER = 19, HEX_INTEGER = 20, BIN_INTEGER = 21, OPEN_PAREN = 22, 20 | CLOSE_PAREN = 23, COMMA = 24, COLON = 25, ASSIGN = 26, PLUS = 27, AT = 28, 21 | PARAGRAPH = 29, OPEN_BRACE = 30, CLOSE_BRACE = 31, OPEN_SHARP = 32, 22 | CLOSE_SHARP = 33, DECIMAL = 34, SKIP_ = 35, UNKNOWN_CHAR = 36 23 | }; 24 | 25 | explicit SsbScriptLexer(antlr4::CharStream *input); 26 | 27 | ~SsbScriptLexer() override; 28 | 29 | 30 | std::string getGrammarFileName() const override; 31 | 32 | const std::vector& getRuleNames() const override; 33 | 34 | const std::vector& getChannelNames() const override; 35 | 36 | const std::vector& getModeNames() const override; 37 | 38 | const antlr4::dfa::Vocabulary& getVocabulary() const override; 39 | 40 | antlr4::atn::SerializedATNView getSerializedATN() const override; 41 | 42 | const antlr4::atn::ATN& getATN() const override; 43 | 44 | // By default the static state used to implement the lexer is lazily initialized during the first 45 | // call to the constructor. You can call this function if you wish to initialize the static state 46 | // ahead of time. 47 | static void initialize(); 48 | 49 | private: 50 | 51 | // Individual action functions triggered by action() above. 52 | 53 | // Individual semantic predicate functions triggered by sempred() above. 54 | 55 | }; 56 | 57 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/position_marker_arg.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.common_syntax import parse_position_marker_arg 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | 29 | 30 | class PositionMarkerArgCompileHandler(AbstractCompileHandler[ExplorerScriptParser.Position_marker_argContext, None]): 31 | def collect(self) -> tuple[int, int]: # position, offset 32 | pos, offset = parse_position_marker_arg(self.ctx) 33 | return pos, offset 34 | 35 | def add(self, obj: None) -> None: 36 | # Doesn't accept anything. 37 | self._raise_add_error(obj) 38 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/switch_headers/sector.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 27 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 28 | from explorerscript.ssb_converting.ssb_special_ops import OP_SWITCH_SECTOR 29 | 30 | 31 | class SwitchHeaderSectorCompileHandler(AbstractCompileHandler[ExplorerScriptParser.Switch_h_sectorContext, None]): 32 | def collect(self) -> SsbOperation: 33 | return self._generate_operation(OP_SWITCH_SECTOR, []) 34 | 35 | def add(self, obj: None) -> None: 36 | self._raise_add_error(obj) 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | test_reports/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # Environments 88 | .env 89 | .venv 90 | env/ 91 | venv/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # pytest 107 | pytest.xml 108 | 109 | # mypy 110 | .mypy_cache/ 111 | ### JetBrains 112 | .idea/ 113 | /gen/ 114 | ### skytemple 115 | dbg_output 116 | # Riptide 117 | /_riptide -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools", 4 | "scikit-build-core>=0.10.7, < 0.11", 5 | "pybind11>=2.13.6, < 2.14" 6 | ] 7 | build-backend = "scikit_build_core.setuptools.build_meta" 8 | 9 | [project] 10 | name = "explorerscript" 11 | version = "0.2.4" 12 | authors = [ 13 | { name = 'Marco "Capypara" Köpcke', email = "hello@capypara.de" }, 14 | # see GitHub contributors list for additional people. 15 | ] 16 | description = "ExplorerScript and SSBScript: Script languages for decompiled SSB (Pokémon Mystery Dungeon Explorers of Sky)" 17 | readme = "README.rst" 18 | requires-python = ">=3.10" 19 | keywords = ["rom-hacking", "game-modding", "skytemple"] 20 | license = { text = "MIT" } 21 | classifiers = [ 22 | "Development Status :: 4 - Beta", 23 | 'Programming Language :: Python', 24 | 'License :: OSI Approved :: MIT License', 25 | 'Programming Language :: Python :: 3.10', 26 | 'Programming Language :: Python :: 3.11', 27 | 'Programming Language :: Python :: 3.12', 28 | 'Programming Language :: Python :: 3.13', 29 | ] 30 | dependencies = [ 31 | 'igraph == 0.11.8', 32 | 'typing_extensions >= 4.0; python_version < "3.10"' 33 | ] 34 | 35 | [project.urls] 36 | Homepage = "https://skytemple.org" 37 | Announcements = "https://blog.skytemple.org" 38 | Documentation = "https://wiki.skytemple.org" 39 | Repository = "https://github.com/SkyTemple/ExplorerScript.git" 40 | Issues = "https://github.com/SkyTemple/ExplorerScript/issues" 41 | Discord = "https://discord.gg/skytemple" 42 | 43 | [project.optional-dependencies] 44 | pygments = ["pygments>=2.6.1"] 45 | 46 | [project.entry-points."pygments.lexers"] 47 | expslexer = "explorerscript.pygments.expslexer:ExplorerScriptLexer" 48 | 49 | [tool.setuptools.packages.find] 50 | where = ["."] # list of folders that contain the packages (["."] by default) 51 | include = ["explorerscript*"] 52 | namespaces = false 53 | 54 | [tool.ruff] 55 | line-length = 120 56 | extend-exclude = [ 57 | "antlr4/*" 58 | ] 59 | 60 | [tools.ruff.lint] 61 | select = ["W", "E", "F", "ARG"] 62 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/functions/coro_def.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import Any 26 | 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractFuncdefCompileHandler 28 | from explorerscript.ssb_converting.ssb_data_types import SsbRoutineInfo, SsbRoutineType 29 | from explorerscript_parser import ExplorerScriptParser 30 | 31 | 32 | class CoroDefCompileHandler(AbstractFuncdefCompileHandler[ExplorerScriptParser.Coro_defContext]): 33 | def collect(self) -> Any: 34 | """Collects name of the coroutine, routine info and operations.""" 35 | name = str(self.ctx.IDENTIFIER()) 36 | with self.compiler_ctx.in_funcdef(name): 37 | ops = self.collect_ops() 38 | return str(name), SsbRoutineInfo(SsbRoutineType.COROUTINE, 0), ops 39 | 40 | def get_new_routine_id(self, old_id: int) -> int: 41 | return old_id + 1 42 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/functions/simple_def.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import Any 26 | 27 | from explorerscript_parser import ExplorerScriptParser 28 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractFuncdefCompileHandler 29 | from explorerscript.ssb_converting.ssb_data_types import SsbRoutineInfo, SsbRoutineType 30 | from explorerscript.util import exps_int 31 | 32 | 33 | class SimpleDefCompileHandler(AbstractFuncdefCompileHandler[ExplorerScriptParser.Simple_defContext]): 34 | def collect(self) -> Any: 35 | """Collects routine info and operations.""" 36 | with self.compiler_ctx.in_funcdef(exps_int(str(self.ctx.INTEGER()))): 37 | ops = self.collect_ops() 38 | return SsbRoutineInfo(SsbRoutineType.GENERIC, 0), ops 39 | 40 | def get_new_routine_id(self, old_id: int) -> int: 41 | return exps_int(str(self.ctx.INTEGER())) 42 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/util.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import TYPE_CHECKING 26 | 27 | if TYPE_CHECKING: 28 | from explorerscript.ssb_script.ssb_converting.ssb_decompiler import SsbScriptSsbDecompiler 29 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 30 | 31 | 32 | class Blk: 33 | """Utility context manager for managing indents.""" 34 | 35 | def __init__(self, reader: SsbScriptSsbDecompiler | ExplorerScriptSsbDecompiler, braces: bool = True): 36 | self.reader = reader 37 | self.braces = braces 38 | 39 | def __enter__(self) -> None: 40 | self.reader.indent += 1 41 | if self.braces: 42 | self.reader.write_stmnt(" {", False) 43 | 44 | def __exit__(self, exc_type, exc_value, exc_traceback) -> None: # type: ignore 45 | self.reader.indent -= 1 46 | if self.braces: 47 | self.reader.write_stmnt("}", True) 48 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for generating files. 2 | # Does NOT install the Python package or dependencies. 3 | # Make sure to install those first. 4 | # Make sure the Antlr4 version used matches the one of the runtime package! 5 | 6 | .PHONY := all exps ssbscript explorerscript-installed 7 | .DEFAULT_GOAL := all 8 | 9 | explorerscript_parser/ExplorerScript.interp explorerscript_parser/ExplorerScript.tokens explorerscript_parser/ExplorerScriptLexer.interp explorerscript_parser/ExplorerScriptLexer.h explorerscript_parser/ExplorerScriptLexer.cpp explorerscript_parser/ExplorerScriptLexer.tokens explorerscript_parser/ExplorerScriptParser.h explorerscript_parser/ExplorerScriptParser.cpp explorerscript_parser/ExplorerScriptVisitor.h explorerscript_parser/ExplorerScriptVisitor.cpp: explorerscript_parser/ExplorerScript.g4 explorerscript_parser/SsbCommon.g4 10 | cd explorerscript_parser && antlr4 -Dlanguage=Cpp -no-listener -visitor ExplorerScript.g4 11 | 12 | explorerscript_parser/SsbScript.interp explorerscript_parser/SsbScript.tokens explorerscript_parser/SsbScriptLexer.interp explorerscript_parser/SsbScriptLexer.h explorerscript_parser/SsbScriptLexer.cpp explorerscript_parser/SsbScriptLexer.tokens explorerscript_parser/SsbScriptParser.h explorerscript_parser/SsbScriptParser.cpp: explorerscript_parser/SsbScript.g4 explorerscript_parser/SsbCommon.g4 13 | cd explorerscript_parser && antlr4 -Dlanguage=Cpp -no-listener -visitor SsbScript.g4 14 | 15 | exps: explorerscript_parser/ExplorerScriptParser.cpp 16 | 17 | ssbscript: explorerscript_parser/SsbScriptParser.cpp 18 | 19 | explorerscript_parser/pybind_explorerscript_parser.cpp explorerscript_parser/__init__.pyi: explorerscript_parser/ExplorerScriptLexer.h explorerscript_parser/ExplorerScriptParser.h explorerscript_parser/ExplorerScriptVisitor.h explorerscript_parser/SsbScriptLexer.h explorerscript_parser/SsbScriptParser.h generate_parser_bindings.py 20 | ./generate_parser_bindings.py 21 | ruff format explorerscript_parser/__init__.pyi 22 | 23 | explorerscript-installed: explorerscript_parser/pybind_explorerscript_parser.cpp ExternalAntlr4Cpp.cmake CMakeLists.txt pyproject.toml setup.py 24 | pip install . -v 25 | 26 | all: exps ssbscript explorerscript_parser/pybind_explorerscript_parser.cpp explorerscript_parser/__init__.pyi explorerscript-installed 27 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/ifs/else_block.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import ( 26 | AbstractStatementCompileHandler, 27 | AbstractComplexStatementCompileHandler, 28 | AbstractBlockCompileHandler, 29 | ) 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 31 | from explorerscript_parser import ExplorerScriptParser, Antlr4ParserRuleContext 32 | 33 | 34 | class ElseBlockCompileHandler(AbstractBlockCompileHandler[ExplorerScriptParser.Else_blockContext]): 35 | """Handles an else block.""" 36 | 37 | def collect(self) -> list[SsbOperation]: 38 | return self._process_block() 39 | 40 | def add(self, obj: AbstractStatementCompileHandler[Antlr4ParserRuleContext]) -> None: 41 | if isinstance(obj, AbstractComplexStatementCompileHandler): 42 | # Sub statement for the block 43 | self._added_handlers.append(obj) 44 | return 45 | self._raise_add_error(obj) 46 | -------------------------------------------------------------------------------- /explorerscript/explorerscript_reader.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.error import ParseError 26 | from explorerscript.syntax_error_listener import SyntaxErrorListener 27 | from explorerscript_parser import ExplorerScriptParserWrapper 28 | 29 | 30 | class ExplorerScriptReader: 31 | """Constructs a parsing tree out of ExplorerScript source code.""" 32 | 33 | source_code: str 34 | 35 | def __init__(self, source_code: str): 36 | self.source_code = source_code 37 | 38 | def read(self) -> ExplorerScriptParserWrapper: 39 | """ 40 | :raises: ParseError 41 | """ 42 | error_listener = SyntaxErrorListener() 43 | parser = ExplorerScriptParserWrapper(self.source_code, error_listener) 44 | 45 | # Look for errors 46 | if len(error_listener.syntax_errors) > 0: 47 | # We only return the first error, the rest is probably not relevant, since 48 | # the first screws everything over. 49 | raise ParseError(error_listener.syntax_errors[0]) 50 | 51 | return parser 52 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/functions/macro_def.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractFuncdefCompileHandler 27 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 28 | 29 | 30 | class MacroDefCompileHandler(AbstractFuncdefCompileHandler[ExplorerScriptParser.MacrodefContext]): 31 | def collect(self) -> list[SsbOperation]: 32 | """Collects macro operations.""" 33 | with self.compiler_ctx.in_macrodef(self.get_name()): 34 | return self.collect_ops() 35 | 36 | def get_new_routine_id(self, old_id: int) -> int: 37 | """n/a, use get_name""" 38 | return -1 39 | 40 | def get_name(self) -> str: 41 | """Returns the macro name""" 42 | return str(self.ctx.IDENTIFIER()) 43 | 44 | def get_variables(self) -> list[str]: 45 | vars = [] 46 | for var in self.ctx.VARIABLE(): 47 | vars.append(str(var)) 48 | return vars 49 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/meta_attributes.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import re 26 | from typing import Any 27 | 28 | 29 | class ExpsMetaAttributes: 30 | IsSsbScript = "is-ssb-script" 31 | 32 | 33 | def parse_exps_meta_attributes(explorerscript_src: str) -> dict[str, Any]: 34 | """Parse the attributes of the script. ("//?: attr: value#")""" 35 | attributes = {} 36 | attribute_reader_line = 0 37 | lines = explorerscript_src.splitlines() 38 | if len(lines) < 1: 39 | return {} 40 | regex_attr_line = re.compile(r"//\?:\s*(.*?):\s*(.*)") 41 | while lines[attribute_reader_line].strip().startswith("//?:"): 42 | try: 43 | line = lines[attribute_reader_line] 44 | match = regex_attr_line.search(line) 45 | if match: 46 | key = match.group(1).strip() 47 | value = match.group(2).strip() 48 | attributes[key] = value 49 | else: 50 | break 51 | except Exception: 52 | pass 53 | attribute_reader_line += 1 54 | return attributes 55 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/label.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractStatementCompileHandler 27 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 28 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabel 29 | 30 | 31 | class LabelCompileHandler(AbstractStatementCompileHandler[ExplorerScriptParser.LabelContext]): 32 | def collect(self) -> list[SsbOperation]: 33 | label_name = str(self.ctx.IDENTIFIER()) 34 | 35 | if label_name in self.compiler_ctx.collected_labels: 36 | label = self.compiler_ctx.collected_labels[label_name] 37 | else: 38 | label = SsbLabel(self.compiler_ctx.counter_labels(), -1, f"proper label, named {label_name}", label_name) 39 | self.compiler_ctx.collected_labels[label_name] = label 40 | 41 | return [label] 42 | 43 | def add(self, obj: None) -> None: 44 | # Doesn't accept anything. 45 | self._raise_add_error(obj) 46 | -------------------------------------------------------------------------------- /explorerscript/cli/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import sys 26 | 27 | SETTINGS_PERFORMANCE_PROGRESS_LIST_VAR_NAME = "performance_progress_list_var_name" 28 | SETTINGS_DUNGEON_MODE_CONSTANTS = "dungeon_mode_constants" 29 | SETTINGS = "settings" 30 | SETTINGS_DMC_OPEN = "open" 31 | SETTINGS_DMC_CLOSED = "closed" 32 | SETTINGS_DMC_REQUEST = "request" 33 | SETTINGS_DMC_OPEN_REQUEST = "open_request" 34 | 35 | 36 | def check_settings(settings): # type: ignore 37 | if SETTINGS not in settings: 38 | print("Settings missing.", file=sys.stderr) 39 | exit(1) 40 | settings = settings[SETTINGS] 41 | 42 | if SETTINGS_PERFORMANCE_PROGRESS_LIST_VAR_NAME not in settings: 43 | print(f"'{SETTINGS_PERFORMANCE_PROGRESS_LIST_VAR_NAME}' missing in settings.", file=sys.stderr) 44 | exit(1) 45 | 46 | if SETTINGS_DUNGEON_MODE_CONSTANTS not in settings or not all( 47 | x in settings[SETTINGS_DUNGEON_MODE_CONSTANTS] 48 | for x in [SETTINGS_DMC_OPEN, SETTINGS_DMC_CLOSED, SETTINGS_DMC_REQUEST, SETTINGS_DMC_OPEN_REQUEST] 49 | ): 50 | print(f"'{SETTINGS_DUNGEON_MODE_CONSTANTS}' missing in settings or malformed.", file=sys.stderr) 51 | exit(1) 52 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/assignment_operator.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.ssb_data_types import SsbCalcOperator 29 | 30 | 31 | class AssignOperatorCompileHandler(AbstractCompileHandler[ExplorerScriptParser.Assign_operatorContext, None]): 32 | def collect(self) -> SsbCalcOperator: 33 | self.ctx: ExplorerScriptParser.Assign_operatorContext 34 | if self.ctx.OP_MINUS(): 35 | return SsbCalcOperator.MINUS 36 | if self.ctx.OP_PLUS(): 37 | return SsbCalcOperator.PLUS 38 | if self.ctx.OP_MULTIPLY(): 39 | return SsbCalcOperator.MULTIPLY 40 | if self.ctx.OP_DIVIDE(): 41 | return SsbCalcOperator.DIVIDE 42 | if self.ctx.ASSIGN(): 43 | return SsbCalcOperator.ASSIGN 44 | raise SsbCompilerError("Unknown conditional operator.") 45 | 46 | def add(self, obj: None) -> None: 47 | # Doesn't accept anything. 48 | self._raise_add_error(obj) 49 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/statements/call.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractStatementCompileHandler 27 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 28 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabel, OP_CALL 29 | 30 | 31 | class CallCompileHandler(AbstractStatementCompileHandler[ExplorerScriptParser.CallContext]): 32 | def collect(self) -> list[SsbOperation]: 33 | """ 34 | We generate a label jump (using call) now. 35 | """ 36 | self.ctx: ExplorerScriptParser.CallContext 37 | label_name = str(self.ctx.IDENTIFIER()) 38 | if label_name in self.compiler_ctx.collected_labels: 39 | label = self.compiler_ctx.collected_labels[label_name] 40 | else: 41 | label = SsbLabel(self.compiler_ctx.counter_labels(), -1, f"proper label, named {label_name}", label_name) 42 | self.compiler_ctx.collected_labels[label_name] = label 43 | return [self._generate_jump_operation(OP_CALL, [], label)] 44 | 45 | def add(self, obj: None) -> None: 46 | # supports no added handlers 47 | self._raise_add_error(obj) 48 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compiler_visitor/has_routines_visitor.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import Any 26 | 27 | from explorerscript_parser import ExplorerScriptParser, ExplorerScriptBaseVisitor 28 | 29 | 30 | class HasRoutinesVisitor(ExplorerScriptBaseVisitor): 31 | """Visitor that returns whether or not the ExplorerScript tree contains any routines.""" 32 | 33 | def __init__(self) -> None: 34 | super().__init__() 35 | 36 | def visitImport_stmt(self, ctx: ExplorerScriptParser.Import_stmtContext) -> bool: 37 | # Are not visited. 38 | return False 39 | 40 | def visitFuncdef(self, ctx: ExplorerScriptParser.FuncdefContext) -> bool: 41 | return True 42 | 43 | def visitMacrodef(self, ctx: ExplorerScriptParser.MacrodefContext) -> bool: 44 | # Are not visited. 45 | return False 46 | 47 | def visitConstant_assign(self, ctx: ExplorerScriptParser.Constant_assignContext) -> None: 48 | # Are not visited. 49 | return None 50 | 51 | def defaultResult(self) -> bool: # type: ignore 52 | return False 53 | 54 | def visitTerminal(self, node: Any) -> bool: 55 | return False 56 | 57 | def aggregateResult(self, aggregate: bool, nextResult: bool) -> bool: 58 | return aggregate or nextResult 59 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/loop/forever_block.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import cast 26 | 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import ( 28 | AbstractStatementCompileHandler, 29 | AbstractComplexStatementCompileHandler, 30 | AbstractLoopBlockCompileHandler, 31 | AnyLoopBlockCompileHandler, 32 | ) 33 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 34 | from explorerscript_parser import ExplorerScriptParser, Antlr4ParserRuleContext 35 | 36 | 37 | class ForeverBlockCompileHandler(AbstractLoopBlockCompileHandler[ExplorerScriptParser.Forever_blockContext]): 38 | """Handles an entire forever block.""" 39 | 40 | def collect(self) -> list[SsbOperation]: 41 | with self.compiler_ctx.in_loop(cast(AnyLoopBlockCompileHandler, self)): 42 | retval = [self._start_label] + self._process_block(False) + [self.continue_loop(), self._end_label] 43 | return retval 44 | 45 | def add(self, obj: AbstractStatementCompileHandler[Antlr4ParserRuleContext]) -> None: 46 | if isinstance(obj, AbstractComplexStatementCompileHandler): 47 | # Sub statement for the block 48 | self._added_handlers.append(obj) 49 | return 50 | self._raise_add_error(obj) 51 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/scn_var.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam 31 | from explorerscript.util import _ 32 | 33 | 34 | class ScnVarCompileHandler(AbstractCompileHandler[ExplorerScriptParser.Scn_varContext, PrimitiveCompileHandler]): 35 | def __init__(self, ctx: ExplorerScriptParser.Scn_varContext, compiler_ctx: CompilerCtx): 36 | super().__init__(ctx, compiler_ctx) 37 | self.var_target: SsbOpParam | None = None 38 | 39 | def collect(self) -> SsbOpParam: 40 | if self.var_target is None: 41 | raise SsbCompilerError(_("scn() without a variable.")) 42 | 43 | return self.var_target 44 | 45 | def add(self, obj: PrimitiveCompileHandler) -> None: 46 | if isinstance(obj, PrimitiveCompileHandler): 47 | self.var_target = obj.collect(allow_string=False) 48 | return 49 | 50 | self._raise_add_error(obj) 51 | -------------------------------------------------------------------------------- /explorerscript/syntax_error_listener.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from collections.abc import Sequence 26 | 27 | from explorerscript.util import f, _ 28 | from explorerscript_parser import Antlr4ErrorListener 29 | 30 | 31 | class AntlrSyntaxError: 32 | def __init__(self, recognizer, offendingSymbol, line, column, msg, e): # type: ignore 33 | self.recognizer = recognizer 34 | self.offendingSymbol = offendingSymbol 35 | self.line = line 36 | self.column = column 37 | self.msg = msg 38 | self.e = e 39 | 40 | def __str__(self) -> str: 41 | return f(_("line {self.line}:{self.column}: {self.msg}")) 42 | 43 | 44 | class SyntaxErrorListener(Antlr4ErrorListener): 45 | """General purpose error listener for Antlr""" 46 | 47 | _syntax_errors: list[AntlrSyntaxError] 48 | 49 | def __init__(self): # type: ignore 50 | self._syntax_errors = [] 51 | super().__init__() 52 | 53 | @property 54 | def syntax_errors(self) -> Sequence[AntlrSyntaxError]: 55 | return self._syntax_errors 56 | 57 | def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): # type: ignore 58 | self._syntax_errors.append(AntlrSyntaxError(recognizer, offendingSymbol, line, column, msg, e)) 59 | 60 | def __str__(self) -> str: 61 | return "\n".join(str(e) for e in self.syntax_errors) 62 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/value_of.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam 31 | from explorerscript.util import _ 32 | 33 | 34 | class ValueOfCompileHandler(AbstractCompileHandler[ExplorerScriptParser.Value_ofContext, PrimitiveCompileHandler]): 35 | def __init__(self, ctx: ExplorerScriptParser.Value_ofContext, compiler_ctx: CompilerCtx): 36 | super().__init__(ctx, compiler_ctx) 37 | self.var_target: SsbOpParam | None = None 38 | 39 | def collect(self) -> SsbOpParam: 40 | if self.var_target is None: 41 | raise SsbCompilerError(_("value() without a variable.")) 42 | 43 | return self.var_target 44 | 45 | def add(self, obj: PrimitiveCompileHandler) -> None: 46 | if isinstance(obj, PrimitiveCompileHandler): 47 | self.var_target = obj.collect(allow_string=False) 48 | return 49 | 50 | self._raise_add_error(obj) 51 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/statements/jump.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractStatementCompileHandler 27 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 28 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabel, OP_JUMP 29 | 30 | 31 | class JumpCompileHandler(AbstractStatementCompileHandler[ExplorerScriptParser.JumpContext]): 32 | def collect(self) -> list[SsbOperation]: 33 | """ 34 | We generate a label jump now. This might be removed & merged with the if/switch-case 35 | before it (if applicable and only operation in block), in the appropriate parent handler. 36 | """ 37 | label_name = str(self.ctx.IDENTIFIER()) 38 | if label_name in self.compiler_ctx.collected_labels: 39 | label = self.compiler_ctx.collected_labels[label_name] 40 | else: 41 | label = SsbLabel(self.compiler_ctx.counter_labels(), -1, f"proper label, named {label_name}", label_name) 42 | self.compiler_ctx.collected_labels[label_name] = label 43 | return [self._generate_jump_operation(OP_JUMP, [], label)] 44 | 45 | def add(self, obj: None) -> None: 46 | # supports no added handlers 47 | self._raise_add_error(obj) 48 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/label_jumps/call.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import logging 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler 31 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabelJump 32 | 33 | if TYPE_CHECKING: 34 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 35 | 36 | logger = logging.getLogger(__name__) 37 | 38 | 39 | class CallWriteHandler(AbstractWriteHandler): 40 | """Handles writing call.""" 41 | 42 | def __init__( 43 | self, start_vertex: Vertex, decompiler: ExplorerScriptSsbDecompiler, parent: AbstractWriteHandler | None 44 | ): 45 | super().__init__(start_vertex, decompiler, parent) 46 | 47 | def write_content(self) -> Vertex | None: 48 | logger.debug("Handling a call; (%s)...", self.start_vertex["op"]) 49 | op: SsbLabelJump = self.start_vertex["op"] 50 | self.decompiler.source_map_add_opcode(op.offset) 51 | assert op.label is not None 52 | self.decompiler.write_stmnt(f"call @label_{op.label.id};") 53 | exits = self.start_vertex.out_edges() 54 | assert 3 > len(exits) > 0, f"A call must have exactly one or two points to jump to, has {len(exits)}." 55 | return exits[0].target_vertex 56 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/operations/arg.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import Union 26 | 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.position_marker import PositionMarkerCompileHandler 29 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 30 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 31 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam 32 | from explorerscript_parser import Antlr4ParserRuleContext 33 | 34 | _SupportedHandlers = Union[PrimitiveCompileHandler, PositionMarkerCompileHandler] 35 | 36 | 37 | class ArgCompileHandler(AbstractCompileHandler[Antlr4ParserRuleContext, _SupportedHandlers]): 38 | def __init__(self, ctx: Antlr4ParserRuleContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.arg_handler: _SupportedHandlers | None = None 41 | 42 | def collect(self) -> SsbOpParam: 43 | assert self.arg_handler is not None 44 | return self.arg_handler.collect() 45 | 46 | def add(self, obj: _SupportedHandlers) -> None: 47 | if isinstance(obj, PrimitiveCompileHandler) or isinstance(obj, PositionMarkerCompileHandler): 48 | self.arg_handler = obj 49 | return 50 | self._raise_add_error(obj) 51 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/statements/control_statement.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractStatementCompileHandler 27 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 28 | from explorerscript.ssb_converting.ssb_special_ops import OP_HOLD, OP_END, OP_RETURN 29 | 30 | 31 | class ControlStatementCompileHandler(AbstractStatementCompileHandler[ExplorerScriptParser.Cntrl_stmtContext]): 32 | def collect(self) -> list[SsbOperation]: 33 | ops = [] 34 | if self.ctx.RETURN(): 35 | ops.append(self._generate_operation(OP_RETURN, [])) 36 | elif self.ctx.END(): 37 | ops.append(self._generate_operation(OP_END, [])) 38 | elif self.ctx.HOLD(): 39 | ops.append(self._generate_operation(OP_HOLD, [])) 40 | elif self.ctx.CONTINUE(): 41 | ops.append(self._register_operation(self.compiler_ctx.continue_loop(self.ctx))) 42 | elif self.ctx.BREAK(): 43 | ops.append(self._register_operation(self.compiler_ctx.break_case(self.ctx))) 44 | elif self.ctx.BREAK_LOOP(): 45 | ops.append(self._register_operation(self.compiler_ctx.break_loop(self.ctx))) 46 | 47 | return ops 48 | 49 | def add(self, obj: None) -> None: 50 | # supports no added handlers 51 | self._raise_add_error(obj) 52 | -------------------------------------------------------------------------------- /explorerscript_parser/SsbScriptVisitor.h: -------------------------------------------------------------------------------- 1 | 2 | // Generated from SsbScript.g4 by ANTLR 4.13.0 3 | 4 | #pragma once 5 | 6 | 7 | #include "antlr4-runtime.h" 8 | #include "SsbScriptParser.h" 9 | 10 | 11 | 12 | /** 13 | * This class defines an abstract visitor for a parse tree 14 | * produced by SsbScriptParser. 15 | */ 16 | class SsbScriptVisitor : public antlr4::tree::AbstractParseTreeVisitor { 17 | public: 18 | 19 | /** 20 | * Visit parse trees produced by SsbScriptParser. 21 | */ 22 | virtual std::any visitPos_argument(SsbScriptParser::Pos_argumentContext *context) = 0; 23 | 24 | virtual std::any visitJump_marker(SsbScriptParser::Jump_markerContext *context) = 0; 25 | 26 | virtual std::any visitStart(SsbScriptParser::StartContext *context) = 0; 27 | 28 | virtual std::any visitFuncdef(SsbScriptParser::FuncdefContext *context) = 0; 29 | 30 | virtual std::any visitSimple_def(SsbScriptParser::Simple_defContext *context) = 0; 31 | 32 | virtual std::any visitCoro_def(SsbScriptParser::Coro_defContext *context) = 0; 33 | 34 | virtual std::any visitFor_target_def(SsbScriptParser::For_target_defContext *context) = 0; 35 | 36 | virtual std::any visitPrimitive(SsbScriptParser::PrimitiveContext *context) = 0; 37 | 38 | virtual std::any visitStmt(SsbScriptParser::StmtContext *context) = 0; 39 | 40 | virtual std::any visitOperation(SsbScriptParser::OperationContext *context) = 0; 41 | 42 | virtual std::any visitInline_ctx(SsbScriptParser::Inline_ctxContext *context) = 0; 43 | 44 | virtual std::any visitFunc_suite(SsbScriptParser::Func_suiteContext *context) = 0; 45 | 46 | virtual std::any visitFunc_alias(SsbScriptParser::Func_aliasContext *context) = 0; 47 | 48 | virtual std::any visitArglist(SsbScriptParser::ArglistContext *context) = 0; 49 | 50 | virtual std::any visitPosition_marker(SsbScriptParser::Position_markerContext *context) = 0; 51 | 52 | virtual std::any visitPosition_marker_arg(SsbScriptParser::Position_marker_argContext *context) = 0; 53 | 54 | virtual std::any visitLabel(SsbScriptParser::LabelContext *context) = 0; 55 | 56 | virtual std::any visitString(SsbScriptParser::StringContext *context) = 0; 57 | 58 | virtual std::any visitLang_string(SsbScriptParser::Lang_stringContext *context) = 0; 59 | 60 | virtual std::any visitLang_string_argument(SsbScriptParser::Lang_string_argumentContext *context) = 0; 61 | 62 | virtual std::any visitString_value(SsbScriptParser::String_valueContext *context) = 0; 63 | 64 | virtual std::any visitCtx_header(SsbScriptParser::Ctx_headerContext *context) = 0; 65 | 66 | virtual std::any visitFor_target_def_target(SsbScriptParser::For_target_def_targetContext *context) = 0; 67 | 68 | 69 | }; 70 | 71 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compiler_visitor/import_visitor.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import Any 26 | 27 | from explorerscript.ssb_converting.compiler.utils import singleline_string_literal 28 | from explorerscript_parser import ExplorerScriptParser, ExplorerScriptBaseVisitor 29 | 30 | 31 | class ImportVisitor(ExplorerScriptBaseVisitor): 32 | """Returns the list of files to import from an ExplorerScript parsing tree.""" 33 | 34 | def __init__(self) -> None: 35 | super().__init__() 36 | 37 | def visitImport_stmt(self, ctx: ExplorerScriptParser.Import_stmtContext) -> str: 38 | return singleline_string_literal(str(ctx.STRING_LITERAL())) 39 | 40 | def visitFuncdef(self, ctx: ExplorerScriptParser.FuncdefContext) -> None: 41 | # Are not visited. 42 | return None 43 | 44 | def visitMacrodef(self, ctx: ExplorerScriptParser.MacrodefContext) -> None: 45 | # Are not visited. 46 | return None 47 | 48 | def visitConstant_assign(self, ctx: ExplorerScriptParser.Constant_assignContext) -> None: 49 | # Are not visited. 50 | return None 51 | 52 | def defaultResult(self) -> list[str]: # type: ignore 53 | return [] 54 | 55 | def visitTerminal(self, node: Any) -> None: 56 | return None 57 | 58 | def aggregateResult(self, aggregate: list[str], nextResult: str) -> list[str]: 59 | if nextResult is not None: 60 | aggregate.append(nextResult) 61 | return aggregate 62 | -------------------------------------------------------------------------------- /explorerscript_parser/ExplorerScriptLexer.h: -------------------------------------------------------------------------------- 1 | 2 | // Generated from ExplorerScript.g4 by ANTLR 4.13.0 3 | 4 | #pragma once 5 | 6 | 7 | #include "antlr4-runtime.h" 8 | 9 | 10 | 11 | 12 | class ExplorerScriptLexer : public antlr4::Lexer { 13 | public: 14 | enum { 15 | T__0 = 1, OP_FALSE = 2, OP_TRUE = 3, ASSIGN = 4, OPEN_SHARP = 5, CLOSE_SHARP = 6, 16 | OP_EQ = 7, OP_LE = 8, OP_GE = 9, OP_NEQ = 10, OP_AND = 11, OP_XOR = 12, 17 | OP_BICH = 13, OP_MINUS = 14, OP_PLUS = 15, OP_MULTIPLY = 16, OP_DIVIDE = 17, 18 | OR = 18, NOT = 19, JUMP = 20, CALL = 21, IMPORT = 22, CONST = 23, MACRO = 24, 19 | IF = 25, ELSEIF = 26, ELSE = 27, FOREVER = 28, WITH = 29, SWITCH = 30, 20 | RETURN = 31, END = 32, HOLD = 33, CONTINUE = 34, BREAK = 35, BREAK_LOOP = 36, 21 | VALUE = 37, DEBUG = 38, EDIT = 39, VARIATION = 40, RANDOM = 41, SECTOR = 42, 22 | DUNGEON_MODE = 43, MENU2 = 44, MENU = 45, CASE = 46, DEFAULT = 47, CLEAR = 48, 23 | RESET = 49, INIT = 50, SCN = 51, DUNGEON_RESULT = 52, ADVENTURE_LOG = 53, 24 | MESSAGE_SWITCH_TALK = 54, MESSAGE_SWITCH_MONOLOGUE = 55, WHILE = 56, 25 | OPEN_BRACKET = 57, CLOSE_BRACKET = 58, STRING_LITERAL = 59, MULTILINE_STRING_LITERAL = 60, 26 | FOR_TARGET = 61, CORO = 62, DEF = 63, FOR_ACTOR = 64, FOR_OBJECT = 65, 27 | FOR_PERFORMER = 66, ALIAS = 67, FOR = 68, PREVIOUS = 69, POSITION = 70, 28 | IDENTIFIER = 71, VARIABLE = 72, MACRO_CALL = 73, INTEGER = 74, DECIMAL_INTEGER = 75, 29 | OCT_INTEGER = 76, HEX_INTEGER = 77, BIN_INTEGER = 78, OPEN_PAREN = 79, 30 | CLOSE_PAREN = 80, COMMA = 81, COLON = 82, PLUS = 83, AT = 84, PARAGRAPH = 85, 31 | OPEN_BRACE = 86, CLOSE_BRACE = 87, DECIMAL = 88, SKIP_ = 89, UNKNOWN_CHAR = 90 32 | }; 33 | 34 | explicit ExplorerScriptLexer(antlr4::CharStream *input); 35 | 36 | ~ExplorerScriptLexer() override; 37 | 38 | 39 | std::string getGrammarFileName() const override; 40 | 41 | const std::vector& getRuleNames() const override; 42 | 43 | const std::vector& getChannelNames() const override; 44 | 45 | const std::vector& getModeNames() const override; 46 | 47 | const antlr4::dfa::Vocabulary& getVocabulary() const override; 48 | 49 | antlr4::atn::SerializedATNView getSerializedATN() const override; 50 | 51 | const antlr4::atn::ATN& getATN() const override; 52 | 53 | // By default the static state used to implement the lexer is lazily initialized during the first 54 | // call to the constructor. You can call this function if you wish to initialize the static state 55 | // ahead of time. 56 | static void initialize(); 57 | 58 | private: 59 | 60 | // Individual action functions triggered by action() above. 61 | 62 | // Individual semantic predicate functions triggered by sempred() above. 63 | 64 | }; 65 | 66 | -------------------------------------------------------------------------------- /explorerscript_parser/ExplorerScript.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | OP_FALSE=2 3 | OP_TRUE=3 4 | ASSIGN=4 5 | OPEN_SHARP=5 6 | CLOSE_SHARP=6 7 | OP_EQ=7 8 | OP_LE=8 9 | OP_GE=9 10 | OP_NEQ=10 11 | OP_AND=11 12 | OP_XOR=12 13 | OP_BICH=13 14 | OP_MINUS=14 15 | OP_PLUS=15 16 | OP_MULTIPLY=16 17 | OP_DIVIDE=17 18 | OR=18 19 | NOT=19 20 | JUMP=20 21 | CALL=21 22 | IMPORT=22 23 | CONST=23 24 | MACRO=24 25 | IF=25 26 | ELSEIF=26 27 | ELSE=27 28 | FOREVER=28 29 | WITH=29 30 | SWITCH=30 31 | RETURN=31 32 | END=32 33 | HOLD=33 34 | CONTINUE=34 35 | BREAK=35 36 | BREAK_LOOP=36 37 | VALUE=37 38 | DEBUG=38 39 | EDIT=39 40 | VARIATION=40 41 | RANDOM=41 42 | SECTOR=42 43 | DUNGEON_MODE=43 44 | MENU2=44 45 | MENU=45 46 | CASE=46 47 | DEFAULT=47 48 | CLEAR=48 49 | RESET=49 50 | INIT=50 51 | SCN=51 52 | DUNGEON_RESULT=52 53 | ADVENTURE_LOG=53 54 | MESSAGE_SWITCH_TALK=54 55 | MESSAGE_SWITCH_MONOLOGUE=55 56 | WHILE=56 57 | OPEN_BRACKET=57 58 | CLOSE_BRACKET=58 59 | STRING_LITERAL=59 60 | MULTILINE_STRING_LITERAL=60 61 | FOR_TARGET=61 62 | CORO=62 63 | DEF=63 64 | FOR_ACTOR=64 65 | FOR_OBJECT=65 66 | FOR_PERFORMER=66 67 | ALIAS=67 68 | FOR=68 69 | PREVIOUS=69 70 | POSITION=70 71 | IDENTIFIER=71 72 | VARIABLE=72 73 | MACRO_CALL=73 74 | INTEGER=74 75 | DECIMAL_INTEGER=75 76 | OCT_INTEGER=76 77 | HEX_INTEGER=77 78 | BIN_INTEGER=78 79 | OPEN_PAREN=79 80 | CLOSE_PAREN=80 81 | COMMA=81 82 | COLON=82 83 | PLUS=83 84 | AT=84 85 | PARAGRAPH=85 86 | OPEN_BRACE=86 87 | CLOSE_BRACE=87 88 | DECIMAL=88 89 | SKIP_=89 90 | UNKNOWN_CHAR=90 91 | ';'=1 92 | 'FALSE'=2 93 | 'TRUE'=3 94 | '='=4 95 | '<'=5 96 | '>'=6 97 | '=='=7 98 | '<='=8 99 | '>='=9 100 | '!='=10 101 | '&'=11 102 | '^'=12 103 | '&<<'=13 104 | '-='=14 105 | '+='=15 106 | '*='=16 107 | '/='=17 108 | '||'=18 109 | 'not'=19 110 | 'jump'=20 111 | 'call'=21 112 | 'import'=22 113 | 'const'=23 114 | 'macro'=24 115 | 'if'=25 116 | 'elseif'=26 117 | 'else'=27 118 | 'forever'=28 119 | 'with'=29 120 | 'switch'=30 121 | 'return'=31 122 | 'end'=32 123 | 'hold'=33 124 | 'continue'=34 125 | 'break'=35 126 | 'break_loop'=36 127 | 'value'=37 128 | 'debug'=38 129 | 'edit'=39 130 | 'variation'=40 131 | 'random'=41 132 | 'sector'=42 133 | 'dungeon_mode'=43 134 | 'menu2'=44 135 | 'menu'=45 136 | 'case'=46 137 | 'default'=47 138 | 'clear'=48 139 | 'reset'=49 140 | 'init'=50 141 | 'scn'=51 142 | 'dungeon_result'=52 143 | 'adventure_log'=53 144 | 'message_SwitchTalk'=54 145 | 'message_SwitchMonologue'=55 146 | 'while'=56 147 | '['=57 148 | ']'=58 149 | 'coro'=62 150 | 'def'=63 151 | 'for_actor'=64 152 | 'for_object'=65 153 | 'for_performer'=66 154 | 'alias'=67 155 | 'for'=68 156 | 'previous'=69 157 | 'Position'=70 158 | '('=79 159 | ')'=80 160 | ','=81 161 | ':'=82 162 | '+'=83 163 | '@'=84 164 | '§'=85 165 | '{'=86 166 | '}'=87 167 | -------------------------------------------------------------------------------- /explorerscript_parser/ExplorerScriptLexer.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | OP_FALSE=2 3 | OP_TRUE=3 4 | ASSIGN=4 5 | OPEN_SHARP=5 6 | CLOSE_SHARP=6 7 | OP_EQ=7 8 | OP_LE=8 9 | OP_GE=9 10 | OP_NEQ=10 11 | OP_AND=11 12 | OP_XOR=12 13 | OP_BICH=13 14 | OP_MINUS=14 15 | OP_PLUS=15 16 | OP_MULTIPLY=16 17 | OP_DIVIDE=17 18 | OR=18 19 | NOT=19 20 | JUMP=20 21 | CALL=21 22 | IMPORT=22 23 | CONST=23 24 | MACRO=24 25 | IF=25 26 | ELSEIF=26 27 | ELSE=27 28 | FOREVER=28 29 | WITH=29 30 | SWITCH=30 31 | RETURN=31 32 | END=32 33 | HOLD=33 34 | CONTINUE=34 35 | BREAK=35 36 | BREAK_LOOP=36 37 | VALUE=37 38 | DEBUG=38 39 | EDIT=39 40 | VARIATION=40 41 | RANDOM=41 42 | SECTOR=42 43 | DUNGEON_MODE=43 44 | MENU2=44 45 | MENU=45 46 | CASE=46 47 | DEFAULT=47 48 | CLEAR=48 49 | RESET=49 50 | INIT=50 51 | SCN=51 52 | DUNGEON_RESULT=52 53 | ADVENTURE_LOG=53 54 | MESSAGE_SWITCH_TALK=54 55 | MESSAGE_SWITCH_MONOLOGUE=55 56 | WHILE=56 57 | OPEN_BRACKET=57 58 | CLOSE_BRACKET=58 59 | STRING_LITERAL=59 60 | MULTILINE_STRING_LITERAL=60 61 | FOR_TARGET=61 62 | CORO=62 63 | DEF=63 64 | FOR_ACTOR=64 65 | FOR_OBJECT=65 66 | FOR_PERFORMER=66 67 | ALIAS=67 68 | FOR=68 69 | PREVIOUS=69 70 | POSITION=70 71 | IDENTIFIER=71 72 | VARIABLE=72 73 | MACRO_CALL=73 74 | INTEGER=74 75 | DECIMAL_INTEGER=75 76 | OCT_INTEGER=76 77 | HEX_INTEGER=77 78 | BIN_INTEGER=78 79 | OPEN_PAREN=79 80 | CLOSE_PAREN=80 81 | COMMA=81 82 | COLON=82 83 | PLUS=83 84 | AT=84 85 | PARAGRAPH=85 86 | OPEN_BRACE=86 87 | CLOSE_BRACE=87 88 | DECIMAL=88 89 | SKIP_=89 90 | UNKNOWN_CHAR=90 91 | ';'=1 92 | 'FALSE'=2 93 | 'TRUE'=3 94 | '='=4 95 | '<'=5 96 | '>'=6 97 | '=='=7 98 | '<='=8 99 | '>='=9 100 | '!='=10 101 | '&'=11 102 | '^'=12 103 | '&<<'=13 104 | '-='=14 105 | '+='=15 106 | '*='=16 107 | '/='=17 108 | '||'=18 109 | 'not'=19 110 | 'jump'=20 111 | 'call'=21 112 | 'import'=22 113 | 'const'=23 114 | 'macro'=24 115 | 'if'=25 116 | 'elseif'=26 117 | 'else'=27 118 | 'forever'=28 119 | 'with'=29 120 | 'switch'=30 121 | 'return'=31 122 | 'end'=32 123 | 'hold'=33 124 | 'continue'=34 125 | 'break'=35 126 | 'break_loop'=36 127 | 'value'=37 128 | 'debug'=38 129 | 'edit'=39 130 | 'variation'=40 131 | 'random'=41 132 | 'sector'=42 133 | 'dungeon_mode'=43 134 | 'menu2'=44 135 | 'menu'=45 136 | 'case'=46 137 | 'default'=47 138 | 'clear'=48 139 | 'reset'=49 140 | 'init'=50 141 | 'scn'=51 142 | 'dungeon_result'=52 143 | 'adventure_log'=53 144 | 'message_SwitchTalk'=54 145 | 'message_SwitchMonologue'=55 146 | 'while'=56 147 | '['=57 148 | ']'=58 149 | 'coro'=62 150 | 'def'=63 151 | 'for_actor'=64 152 | 'for_object'=65 153 | 'for_performer'=66 154 | 'alias'=67 155 | 'for'=68 156 | 'previous'=69 157 | 'Position'=70 158 | '('=79 159 | ')'=80 160 | ','=81 161 | ':'=82 162 | '+'=83 163 | '@'=84 164 | '§'=85 165 | '{'=86 166 | '}'=87 167 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/switch_headers/random.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam, SsbOperation 31 | from explorerscript.ssb_converting.ssb_special_ops import OP_SWITCH_RANDOM 32 | from explorerscript.util import _ 33 | 34 | 35 | class SwitchHeaderRandomCompileHandler( 36 | AbstractCompileHandler[ExplorerScriptParser.Switch_h_randomContext, PrimitiveCompileHandler] 37 | ): 38 | def __init__(self, ctx: ExplorerScriptParser.Switch_h_randomContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.value: SsbOpParam | None = None 41 | 42 | def collect(self) -> SsbOperation: 43 | if self.value is None: 44 | raise SsbCompilerError(_("No value set for random switch condition.")) 45 | 46 | return self._generate_operation(OP_SWITCH_RANDOM, [self.value]) 47 | 48 | def add(self, obj: PrimitiveCompileHandler) -> None: 49 | if isinstance(obj, PrimitiveCompileHandler): 50 | self.value = obj.collect(allow_string=False) 51 | return 52 | 53 | self._raise_add_error(obj) 54 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/assignment_clear.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractIntegerAssignmentCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 31 | from explorerscript.ssb_converting.ssb_special_ops import OPS_FLAG__CLEAR 32 | from explorerscript.util import _ 33 | 34 | 35 | class AssignmentClearCompileHandler( 36 | AbstractIntegerAssignmentCompileHandler[ExplorerScriptParser.Assignment_clearContext] 37 | ): 38 | def __init__(self, ctx: ExplorerScriptParser.Assignment_clearContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.var_target: SsbOpParam | None = None 41 | 42 | def collect(self) -> list[SsbOperation]: 43 | if self.var_target is None: 44 | raise SsbCompilerError(_("No variable for clear.")) 45 | 46 | return [self._generate_operation(OPS_FLAG__CLEAR, [self.var_target])] 47 | 48 | def add(self, obj: PrimitiveCompileHandler) -> None: 49 | if isinstance(obj, PrimitiveCompileHandler): 50 | self.var_target = obj.collect(allow_string=False) 51 | return 52 | 53 | self._raise_add_error(obj) 54 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/assignment_initial.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractIntegerAssignmentCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 31 | from explorerscript.ssb_converting.ssb_special_ops import OPS_FLAG__INITIAL 32 | from explorerscript.util import _ 33 | 34 | 35 | class AssignmentInitialCompileHandler( 36 | AbstractIntegerAssignmentCompileHandler[ExplorerScriptParser.Assignment_initialContext] 37 | ): 38 | def __init__(self, ctx: ExplorerScriptParser.Assignment_initialContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.var_target: SsbOpParam | None = None 41 | 42 | def collect(self) -> list[SsbOperation]: 43 | if self.var_target is None: 44 | raise SsbCompilerError(_("No variable for init.")) 45 | 46 | return [self._generate_operation(OPS_FLAG__INITIAL, [self.var_target])] 47 | 48 | def add(self, obj: PrimitiveCompileHandler) -> None: 49 | if isinstance(obj, PrimitiveCompileHandler): 50 | self.var_target = obj.collect(allow_string=False) 51 | return 52 | 53 | self._raise_add_error(obj) 54 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/label_jumps/jump.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import logging 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler 31 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabelJump 32 | 33 | if TYPE_CHECKING: 34 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 35 | 36 | logger = logging.getLogger(__name__) 37 | 38 | 39 | class JumpWriteHandler(AbstractWriteHandler): 40 | """Handles writing regular label jump.""" 41 | 42 | def __init__( 43 | self, start_vertex: Vertex, decompiler: ExplorerScriptSsbDecompiler, parent: AbstractWriteHandler | None 44 | ): 45 | super().__init__(start_vertex, decompiler, parent) 46 | 47 | def write_content(self) -> Vertex | None: 48 | """Delegates to the handlers in .label_jump""" 49 | logger.debug("Handling a jump; (%s)...", self.start_vertex["op"]) 50 | op: SsbLabelJump = self.start_vertex["op"] 51 | # TODO: Writing this source map entry may be confusing, if no jump is written next (by the label handler)... 52 | self.decompiler.source_map_add_opcode(op.offset) 53 | # Nothing to do, this is dealt with, when processing the label after this 54 | # either we print a jump there, or we just proceed. 55 | exits = self.start_vertex.out_edges() 56 | assert len(exits) == 1, "A jump must have exactly one point to jump to" 57 | return exits[0].target_vertex 58 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/assignment_adventure_log.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractIntegerAssignmentCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 31 | from explorerscript.ssb_converting.ssb_special_ops import OPS_FLAG__SET_ADVENTURE_LOG 32 | from explorerscript.util import _ 33 | 34 | 35 | class AssignmentAdventureLogCompileHandler( 36 | AbstractIntegerAssignmentCompileHandler[ExplorerScriptParser.Assignment_adv_logContext] 37 | ): 38 | def __init__(self, ctx: ExplorerScriptParser.Assignment_adv_logContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.value: SsbOpParam | None = None 41 | 42 | def collect(self) -> list[SsbOperation]: 43 | if self.value is None: 44 | raise SsbCompilerError(_("No value for adventure_log set.")) 45 | 46 | return [self._generate_operation(OPS_FLAG__SET_ADVENTURE_LOG, [self.value])] 47 | 48 | def add(self, obj: PrimitiveCompileHandler) -> None: 49 | if isinstance(obj, PrimitiveCompileHandler): 50 | self.value = obj.collect(allow_string=False) 51 | return 52 | 53 | self._raise_add_error(obj) 54 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/switch_headers/dungeon_mode.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam, SsbOperation 31 | from explorerscript.ssb_converting.ssb_special_ops import OP_SWITCH_DUNGEON_MODE 32 | from explorerscript.util import _ 33 | 34 | 35 | class SwitchHeaderDungeonModeCompileHandler( 36 | AbstractCompileHandler[ExplorerScriptParser.Switch_h_dungeon_modeContext, PrimitiveCompileHandler] 37 | ): 38 | def __init__(self, ctx: ExplorerScriptParser.Switch_h_dungeon_modeContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.value: SsbOpParam | None = None 41 | 42 | def collect(self) -> SsbOperation: 43 | if self.value is None: 44 | raise SsbCompilerError(_("No dungeon id set for dungeon_mode switch condition.")) 45 | 46 | return self._generate_operation(OP_SWITCH_DUNGEON_MODE, [self.value]) 47 | 48 | def add(self, obj: PrimitiveCompileHandler) -> None: 49 | if isinstance(obj, PrimitiveCompileHandler): 50 | self.value = obj.collect(allow_string=False) 51 | return 52 | 53 | self._raise_add_error(obj) 54 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/abstract.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from abc import ABC, abstractmethod 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | if TYPE_CHECKING: 31 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 32 | 33 | 34 | class AbstractWriteHandler(ABC): 35 | """ 36 | Handles the writing of a single operation, statement, block, routine, etc. 37 | The start vertex is passed by the parent handler to specify where this handler should begin. 38 | """ 39 | 40 | start_vertex: Vertex 41 | decompiler: ExplorerScriptSsbDecompiler 42 | # Parent write handler. 43 | parent: AbstractWriteHandler | None 44 | ended_on_jump: bool 45 | 46 | def __init__( 47 | self, start_vertex: Vertex, decompiler: ExplorerScriptSsbDecompiler, parent: AbstractWriteHandler | None 48 | ): 49 | self.start_vertex = start_vertex 50 | self.decompiler = decompiler 51 | self.parent = parent 52 | self.ended_on_jump = False 53 | 54 | @abstractmethod 55 | def write_content(self) -> Vertex | None: 56 | """ 57 | Writes all operations that this handler is made for, and then 58 | returns the next vertex to process for the parent handler (if applicable). 59 | """ 60 | pass 61 | 62 | 63 | class NestedBlockDisallowedError(Exception): 64 | pass 65 | 66 | 67 | class FallbackToJump(Exception): 68 | """Raised when a label jump write handler can not do 69 | it's task and the default jump handler should be used instead.""" 70 | 71 | pass 72 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/conditional_operator.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.ssb_data_types import SsbOperator 29 | 30 | 31 | class ConditionalOperatorCompileHandler(AbstractCompileHandler[ExplorerScriptParser.Conditional_operatorContext, None]): 32 | def collect(self) -> SsbOperator: 33 | self.ctx: ExplorerScriptParser.Conditional_operatorContext 34 | if self.ctx.OP_FALSE(): 35 | return SsbOperator.FALSE 36 | if self.ctx.OP_TRUE(): 37 | return SsbOperator.TRUE 38 | if self.ctx.OP_EQ(): 39 | return SsbOperator.EQ 40 | if self.ctx.OP_GE(): 41 | return SsbOperator.GE 42 | if self.ctx.OP_LE(): 43 | return SsbOperator.LE 44 | if self.ctx.CLOSE_SHARP(): 45 | return SsbOperator.GT 46 | if self.ctx.OPEN_SHARP(): 47 | return SsbOperator.LT 48 | if self.ctx.OP_NEQ(): 49 | return SsbOperator.NOT 50 | if self.ctx.OP_AND(): 51 | return SsbOperator.AND 52 | if self.ctx.OP_XOR(): 53 | return SsbOperator.XOR 54 | if self.ctx.OP_BICH(): 55 | return SsbOperator.BIT_SET 56 | raise SsbCompilerError("Unknown conditional operator.") 57 | 58 | def add(self, obj: None) -> None: 59 | # Doesn't accept anything. 60 | self._raise_add_error(obj) 61 | -------------------------------------------------------------------------------- /explorerscript/util.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from inspect import currentframe 26 | from typing import TYPE_CHECKING, Any 27 | 28 | if TYPE_CHECKING: 29 | from typing import SupportsInt, SupportsIndex 30 | 31 | try: 32 | import builtins 33 | 34 | _ = builtins._ # type: ignore 35 | except Exception: 36 | 37 | def _(a): # type: ignore 38 | return a # type: ignore 39 | 40 | 41 | def open_utf8(file, mode="r", *args, **kwargs): # type: ignore 42 | """Like open, but always uses the utf-8 encoding, on all platforms.""" 43 | return open(file, mode, *args, encoding="utf-8", **kwargs) # type: ignore 44 | 45 | 46 | def exps_int(to_convert: str | SupportsInt | SupportsIndex) -> int: 47 | """Converts to integer, auto-detecting the base (if string).""" 48 | try: 49 | if isinstance(to_convert, str): 50 | return int(to_convert, 0) 51 | return int(to_convert) 52 | except TypeError as e: 53 | raise ValueError("Invalid value for conversion to ExplorerScript integer") from e 54 | 55 | 56 | def f(s: str, additional_locals: Any | None = None) -> str: 57 | """f-strings as a function, for use with translatable strings: f'{techticks}' == f('{techticks}')""" 58 | if additional_locals is None: 59 | additional_locals = {} 60 | frame = currentframe().f_back # type: ignore 61 | s1 = s.replace("'", "\\'").replace("\n", "\\n") 62 | additional_locals.update(frame.f_locals) # type: ignore 63 | try: 64 | return eval(f"f'{s1}'", additional_locals, frame.f_globals) # type: ignore 65 | except SyntaxError: 66 | s1 = s.replace('"', '\\"').replace("\n", "\\n") 67 | return eval(f'f"{s1}"', additional_locals, frame.f_globals) # type: ignore 68 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/atoms/position_marker.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 26 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.position_marker_arg import ( 27 | PositionMarkerArgCompileHandler, 28 | ) 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx, singleline_string_literal 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParamPositionMarker 31 | from explorerscript_parser import ExplorerScriptParser 32 | 33 | 34 | class PositionMarkerCompileHandler( 35 | AbstractCompileHandler[ExplorerScriptParser.Position_markerContext, PositionMarkerArgCompileHandler] 36 | ): 37 | def __init__(self, ctx: ExplorerScriptParser.Position_markerContext, compiler_ctx: CompilerCtx): 38 | super().__init__(ctx, compiler_ctx) 39 | # position, offset 40 | self.x: tuple[int, int] | None = None 41 | self.y: tuple[int, int] | None = None 42 | 43 | def collect(self) -> SsbOpParamPositionMarker: 44 | name = singleline_string_literal(str(self.ctx.STRING_LITERAL())) 45 | assert self.x is not None and self.y is not None 46 | return SsbOpParamPositionMarker( 47 | name=name, x_offset=self.x[1], y_offset=self.y[1], x_relative=self.x[0], y_relative=self.y[0] 48 | ) 49 | 50 | def add(self, obj: PositionMarkerArgCompileHandler) -> None: 51 | if isinstance(obj, PositionMarkerArgCompileHandler): 52 | if self.x is None: 53 | self.x = obj.collect() 54 | else: 55 | self.y = obj.collect() 56 | return 57 | self._raise_add_error(obj) 58 | -------------------------------------------------------------------------------- /example/example_compile.py: -------------------------------------------------------------------------------- 1 | # type: ignore 2 | # MIT License 3 | # 4 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in all 14 | # copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | # 24 | import os 25 | 26 | from explorerscript.source_map_visualizer import SourceMapVisualizer 27 | from explorerscript.ssb_converting.ssb_compiler import ExplorerScriptSsbCompiler 28 | from explorerscript.util import open_utf8 29 | 30 | if __name__ == "__main__": 31 | # testing 32 | base = os.path.dirname(os.path.realpath(__file__)) 33 | file_path = os.path.join(base, "SCRIPT", "base.exps") 34 | with open_utf8(file_path) as f: 35 | exps = f.read() 36 | c = ExplorerScriptSsbCompiler("$DUMMY_VAR", [os.path.join(base, "macros")]).compile(exps, file_path) 37 | print("OPS:") 38 | for op in c.routine_ops[0]: 39 | print(f"{op.offset:10x}: ({op.op_code.id:3}) {op.op_code.name:45} - {op.params}") 40 | print(c.routine_infos) 41 | print(c.named_coroutines) 42 | print(c.source_map.serialize(pretty=True)) 43 | print(c.imports) 44 | print("// SOURCE MAP FOR base.exps:") 45 | print(SourceMapVisualizer(exps, c.source_map).write()) 46 | print("// SOURCE MAP FOR base.exps APPLIED FOR macros1.exps:") 47 | with open_utf8(os.path.join(base, "macros", "dir", "macros1.exps")) as f: 48 | macros1_exps = f.read() 49 | print( 50 | SourceMapVisualizer( 51 | macros1_exps, c.source_map, apply_for_macro_calls=os.path.join("..", "macros", "dir", "macros1.exps") 52 | ).write() 53 | ) 54 | print("// SOURCE MAP FOR base.exps APPLIED FOR macros2.exps:") 55 | with open_utf8(os.path.join(base, "macros", "dir", "macros2.exps")) as f: 56 | macros2_exps = f.read() 57 | print( 58 | SourceMapVisualizer( 59 | macros2_exps, c.source_map, apply_for_macro_calls=os.path.join("..", "macros", "dir", "macros2.exps") 60 | ).write() 61 | ) 62 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/ifs/header/negatable.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 27 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx, SsbLabelJumpBlueprint 28 | from explorerscript.ssb_converting.ssb_data_types import SsbOperator, SsbOpParam 29 | from explorerscript.ssb_converting.ssb_special_ops import OP_BRANCH_DEBUG, OP_BRANCH_EDIT, OP_BRANCH_VARIATION 30 | 31 | 32 | class IfHeaderNegatableCompileHandler(AbstractCompileHandler[ExplorerScriptParser.If_h_negatableContext, None]): 33 | def __init__(self, ctx: ExplorerScriptParser.If_h_negatableContext, compiler_ctx: CompilerCtx): 34 | super().__init__(ctx, compiler_ctx) 35 | self.var_target: SsbOpParam | None = None 36 | self.operator: SsbOperator | None = None 37 | self.value: SsbOpParam | None = None 38 | self.value_is_a_variable = False 39 | 40 | # TODO: Typing is weird. 41 | def collect(self) -> SsbLabelJumpBlueprint: # type: ignore 42 | is_simple_positive = self.ctx.NOT() is None 43 | if self.ctx.DEBUG(): 44 | return SsbLabelJumpBlueprint(self.compiler_ctx, self.ctx, OP_BRANCH_DEBUG, [1 if is_simple_positive else 0]) 45 | if self.ctx.EDIT(): 46 | return SsbLabelJumpBlueprint(self.compiler_ctx, self.ctx, OP_BRANCH_EDIT, [1 if is_simple_positive else 0]) 47 | if self.ctx.VARIATION(): 48 | return SsbLabelJumpBlueprint( 49 | self.compiler_ctx, self.ctx, OP_BRANCH_VARIATION, [1 if is_simple_positive else 0] 50 | ) 51 | 52 | def add(self, obj: None) -> None: 53 | self._raise_add_error(obj) 54 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/foreign_label.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import logging 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler 31 | from explorerscript.ssb_converting.ssb_special_ops import SsbForeignLabel 32 | 33 | if TYPE_CHECKING: 34 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 35 | 36 | logger = logging.getLogger(__name__) 37 | 38 | 39 | class ForeignLabelWriteHandler(AbstractWriteHandler): 40 | """Handles writing foreign labels (references to labels in other routines).""" 41 | 42 | def __init__( 43 | self, 44 | start_vertex: Vertex, 45 | decompiler: ExplorerScriptSsbDecompiler, 46 | parent: AbstractWriteHandler | None, 47 | vertex_that_started_block: Vertex | None, 48 | is_first_vertex_of_block: bool, 49 | ): 50 | super().__init__(start_vertex, decompiler, parent) 51 | self.vertex_that_started_block = vertex_that_started_block 52 | self.is_first_vertex_of_block = is_first_vertex_of_block 53 | 54 | def write_content(self) -> None: 55 | op: SsbForeignLabel = self.start_vertex["op"] 56 | logger.debug("Handling a foreign label (%s)...", op) 57 | exits = self.start_vertex.out_edges() 58 | assert len(exits) == 0 59 | # See note in LabelWriteHandler. 60 | # TODO: Fix typing 61 | previous_vertex_op = self.vertex_that_started_block["op"] if self.is_first_vertex_of_block else None # type: ignore 62 | # We definitely need to print that 63 | self.decompiler.write_label_jump(op.label.id, previous_vertex_op) # type: ignore 64 | return None 65 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/assignment_scenario.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractIntegerAssignmentCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 31 | from explorerscript.ssb_converting.ssb_special_ops import OPS_FLAG__SET_SCENARIO 32 | from explorerscript.util import _ 33 | from explorerscript.util import exps_int 34 | 35 | 36 | class AssignmentScenarioCompileHandler( 37 | AbstractIntegerAssignmentCompileHandler[ExplorerScriptParser.Assignment_scnContext] 38 | ): 39 | def __init__(self, ctx: ExplorerScriptParser.Assignment_scnContext, compiler_ctx: CompilerCtx): 40 | super().__init__(ctx, compiler_ctx) 41 | self.var_target: SsbOpParam | None = None 42 | 43 | def collect(self) -> list[SsbOperation]: 44 | if self.var_target is None: 45 | raise SsbCompilerError(_("No variable for assignment set.")) 46 | 47 | return [ 48 | self._generate_operation( 49 | OPS_FLAG__SET_SCENARIO, 50 | [self.var_target, exps_int(str(self.ctx.INTEGER(0))), exps_int(str(self.ctx.INTEGER(1)))], 51 | ) 52 | ] 53 | 54 | def add(self, obj: PrimitiveCompileHandler) -> None: 55 | if isinstance(obj, PrimitiveCompileHandler): 56 | self.var_target = obj.collect(allow_string=False) 57 | return 58 | 59 | self._raise_add_error(obj) 60 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/assignment_reset.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractAssignmentCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.scn_var import ScnVarCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 31 | from explorerscript.ssb_converting.ssb_special_ops import ( 32 | OPS_FLAG__RESET_DUNGEON_RESULT, 33 | OPS_FLAG__RESET_SCENARIO, 34 | ) 35 | from explorerscript.util import _ 36 | 37 | 38 | class AssignmentResetCompileHandler( 39 | AbstractAssignmentCompileHandler[ExplorerScriptParser.Assignment_resetContext, ScnVarCompileHandler] 40 | ): 41 | def __init__(self, ctx: ExplorerScriptParser.Assignment_resetContext, compiler_ctx: CompilerCtx): 42 | super().__init__(ctx, compiler_ctx) 43 | self.scn_var_target: SsbOpParam | None = None 44 | 45 | def collect(self) -> list[SsbOperation]: 46 | if self.scn_var_target is None and not self.ctx.DUNGEON_RESULT(): 47 | raise SsbCompilerError(_("No target for reset.")) 48 | 49 | if self.ctx.DUNGEON_RESULT(): 50 | return [self._generate_operation(OPS_FLAG__RESET_DUNGEON_RESULT, [])] 51 | 52 | assert self.scn_var_target is not None 53 | return [self._generate_operation(OPS_FLAG__RESET_SCENARIO, [self.scn_var_target])] 54 | 55 | def add(self, obj: ScnVarCompileHandler) -> None: 56 | if isinstance(obj, ScnVarCompileHandler): 57 | self.scn_var_target = obj.collect() 58 | return 59 | 60 | self._raise_add_error(obj) 61 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/operations/arg_list.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.source_map import SourceMapPositionMark 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 27 | from explorerscript.ssb_converting.compiler.compile_handlers.operations.arg import ArgCompileHandler 28 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam, SsbOpParamPositionMarker 29 | from explorerscript_parser import ExplorerScriptParser 30 | 31 | 32 | class ArgListCompileHandler(AbstractCompileHandler[ExplorerScriptParser.ArglistContext, ArgCompileHandler]): 33 | def collect(self) -> list[SsbOpParam]: 34 | ret = [] 35 | for i, h in enumerate(self._added_handlers): 36 | arg = h.collect() 37 | ret.append(arg) 38 | if isinstance(arg, SsbOpParamPositionMarker): 39 | # Collect position marker source map entries 40 | self.compiler_ctx.source_map_builder.add_position_mark( 41 | SourceMapPositionMark( 42 | # Antlr line ids are 1-indexed. 43 | self.ctx.start.line - 1, 44 | self.ctx.start.charPositionInLine, 45 | self.ctx.stop.line - 1, 46 | self.ctx.stop.charPositionInLine, 47 | arg.name, 48 | arg.x_offset, 49 | arg.y_offset, 50 | arg.x_relative, 51 | arg.y_relative, 52 | ) 53 | ) 54 | return ret 55 | 56 | def add(self, obj: ArgCompileHandler) -> None: 57 | if isinstance(obj, ArgCompileHandler): 58 | self._added_handlers.append(obj) 59 | return 60 | self._raise_add_error(obj) 61 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/label_jumps/forever_continue.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import logging 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler, FallbackToJump 31 | 32 | if TYPE_CHECKING: 33 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 34 | 35 | logger = logging.getLogger(__name__) 36 | 37 | 38 | class ForeverContinueWriteHandler(AbstractWriteHandler): 39 | """Handles writing loop continue statements.""" 40 | 41 | def __init__( 42 | self, start_vertex: Vertex, decompiler: ExplorerScriptSsbDecompiler, parent: AbstractWriteHandler | None 43 | ): 44 | super().__init__(start_vertex, decompiler, parent) 45 | 46 | def write_content(self) -> Vertex | None: 47 | """Print a continue (if not implicit) and end""" 48 | logger.debug("Handling a continue; (%s)...", self.start_vertex["op"]) 49 | if len(self.decompiler.forever_start_handler_stack) < 1: 50 | # We REALLY shouldn't land here, if we are outside of a loop, but sometimes loop detection still 51 | # raises some "false positives" and builds loops that have break statements reachable from outside 52 | # the loop 53 | logger.warning("While decompiling, tried to generate continue; outside loop!") 54 | raise FallbackToJump() 55 | if not self._continue_is_implicit(): 56 | self.decompiler.source_map_add_opcode(self.start_vertex["op"].offset) 57 | self.decompiler.write_stmnt("continue; // may be redundant") 58 | return None 59 | 60 | def _continue_is_implicit(self) -> bool: 61 | # TODO: Not implemented, is probably not really possible, unless we do a multi-pass solution. 62 | return False 63 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/blocks/switches/switch_headers/scn.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.scn_var import ScnVarCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOpParam, SsbOperation 31 | from explorerscript.ssb_converting.ssb_special_ops import OP_SWITCH_SCENARIO, OP_SWITCH_SCENARIO_LEVEL 32 | from explorerscript.util import _, f 33 | from explorerscript.util import exps_int 34 | 35 | 36 | class SwitchHeaderScnCompileHandler( 37 | AbstractCompileHandler[ExplorerScriptParser.Switch_h_scnContext, ScnVarCompileHandler] 38 | ): 39 | def __init__(self, ctx: ExplorerScriptParser.Switch_h_scnContext, compiler_ctx: CompilerCtx): 40 | super().__init__(ctx, compiler_ctx) 41 | self.scn_var_target: SsbOpParam | None = None 42 | 43 | def collect(self) -> SsbOperation: 44 | if self.scn_var_target is None: 45 | raise SsbCompilerError(_("No variable set for scn switch condition.")) 46 | 47 | index = exps_int(str(self.ctx.INTEGER())) 48 | if index == 0: 49 | return self._generate_operation(OP_SWITCH_SCENARIO, [self.scn_var_target]) 50 | elif index == 1: 51 | return self._generate_operation(OP_SWITCH_SCENARIO_LEVEL, [self.scn_var_target]) 52 | raise SsbCompilerError(f(_("Index for scn() if condition must be 0 or 1 (line {self.ctx.start.line})."))) 53 | 54 | def add(self, obj: ScnVarCompileHandler) -> None: 55 | if isinstance(obj, ScnVarCompileHandler): 56 | self.scn_var_target = obj.collect() 57 | return 58 | 59 | self._raise_add_error(obj) 60 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/label_jumps/forever_break.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import logging 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler, FallbackToJump 31 | 32 | if TYPE_CHECKING: 33 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 34 | 35 | logger = logging.getLogger(__name__) 36 | 37 | 38 | class ForeverBreakWriteHandler(AbstractWriteHandler): 39 | """Handles writing loop breaks.""" 40 | 41 | def __init__( 42 | self, start_vertex: Vertex, decompiler: ExplorerScriptSsbDecompiler, parent: AbstractWriteHandler | None 43 | ): 44 | super().__init__(start_vertex, decompiler, parent) 45 | 46 | def write_content(self) -> Vertex | None: 47 | """Print a break and end""" 48 | logger.debug("Handling a break_loop; (%s)...", self.start_vertex["op"]) 49 | self.decompiler.source_map_add_opcode(self.start_vertex["op"].offset) 50 | self.decompiler.write_stmnt("break_loop;") 51 | exits = self.start_vertex.out_edges() 52 | if len(exits) == 1: 53 | if len(self.decompiler.forever_start_handler_stack) < 1: 54 | # We REALLY shouldn't land here, if we are outside of a loop, but sometimes loop detection still 55 | # raises some "false positives" and builds loops that have break statements reachable from outside 56 | # the loop 57 | logger.warning("While decompiling, tried to generate break_loop; outside loop!") 58 | raise FallbackToJump() 59 | # Make sure the forever start block is aware of the next vertex! 60 | self.decompiler.forever_start_handler_stack[-1].set_vertex_after(exits[0].target_vertex) 61 | return None 62 | raise ValueError("After a break_loop there must be exactly 1 immediate opcode.") 63 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/assignments/assignment_dungeon_mode.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript_parser import ExplorerScriptParser 26 | from explorerscript.error import SsbCompilerError 27 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractIntegerAssignmentCompileHandler 28 | from explorerscript.ssb_converting.compiler.compile_handlers.atoms.primitive import PrimitiveCompileHandler 29 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 31 | from explorerscript.ssb_converting.ssb_special_ops import OPS_FLAG__SET_DUNGEON_MODE 32 | from explorerscript.util import _ 33 | 34 | 35 | class AssignmentDungeonModeCompileHandler( 36 | AbstractIntegerAssignmentCompileHandler[ExplorerScriptParser.Assignment_dungeon_modeContext] 37 | ): 38 | def __init__(self, ctx: ExplorerScriptParser.Assignment_dungeon_modeContext, compiler_ctx: CompilerCtx): 39 | super().__init__(ctx, compiler_ctx) 40 | self.var_target: SsbOpParam | None = None 41 | self.value: SsbOpParam | None = None 42 | 43 | def collect(self) -> list[SsbOperation]: 44 | if self.var_target is None: 45 | raise SsbCompilerError(_("No variable for dungeon_mode set.")) 46 | if self.value is None: 47 | raise SsbCompilerError(_("No value for dungeon_mode set.")) 48 | 49 | return [self._generate_operation(OPS_FLAG__SET_DUNGEON_MODE, [self.var_target, self.value])] 50 | 51 | def add(self, obj: PrimitiveCompileHandler) -> None: 52 | if isinstance(obj, PrimitiveCompileHandler): 53 | if self.var_target is None: 54 | self.var_target = obj.collect(allow_string=False) 55 | return 56 | if self.value is None: 57 | self.value = obj.collect(allow_string=False) 58 | return 59 | 60 | self._raise_add_error(obj) 61 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handlers/simple_ops/keyword.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from typing import TYPE_CHECKING 26 | 27 | from igraph import Vertex 28 | 29 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler 30 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 31 | from explorerscript.ssb_converting.ssb_special_ops import OP_RETURN, OP_END, OP_HOLD 32 | 33 | if TYPE_CHECKING: 34 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 35 | 36 | 37 | class KeywordSimpleOpWriteHandler(AbstractWriteHandler): 38 | """Handles writing simple opcodes that have special keyword representations in ExplorerScript.""" 39 | 40 | def __init__( 41 | self, start_vertex: Vertex, decompiler: ExplorerScriptSsbDecompiler, parent: AbstractWriteHandler | None 42 | ): 43 | super().__init__(start_vertex, decompiler, parent) 44 | 45 | def write_content(self) -> Vertex | None: 46 | op: SsbOperation = self.start_vertex["op"] 47 | self.decompiler.source_map_add_opcode(op.offset) 48 | if op.op_code.name == OP_RETURN: 49 | self._write_return() 50 | elif op.op_code.name == OP_END: 51 | self._write_end() 52 | elif op.op_code.name == OP_HOLD: 53 | self._write_hold() 54 | else: 55 | raise ValueError(f"Unknown keyword opcode: {op}") 56 | exits = self.start_vertex.out_edges() 57 | if len(exits) == 1: 58 | next_vertex = exits[0].target_vertex 59 | elif len(exits) == 0: 60 | next_vertex = None 61 | else: 62 | raise ValueError("After a simple opcode there must be exactly 0 or 1 immediate opcode.") 63 | return next_vertex 64 | 65 | def _write_return(self) -> None: 66 | self.decompiler.write_return() 67 | 68 | def _write_end(self) -> None: 69 | self.decompiler.write_end() 70 | 71 | def _write_hold(self) -> None: 72 | self.decompiler.write_hold() 73 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/compile_handlers/operations/macro_call.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | from explorerscript.error import SsbCompilerError 26 | from explorerscript.ssb_converting.compiler.compile_handlers.abstract import AbstractComplexStatementCompileHandler 27 | from explorerscript.ssb_converting.compiler.compile_handlers.operations.arg_list import ArgListCompileHandler 28 | from explorerscript.ssb_converting.compiler.utils import CompilerCtx 29 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation, SsbOpParam 30 | from explorerscript.util import _, f 31 | from explorerscript_parser import ExplorerScriptParser 32 | 33 | 34 | class MacroCallCompileHandler( 35 | AbstractComplexStatementCompileHandler[ExplorerScriptParser.Macro_callContext, ArgListCompileHandler] 36 | ): 37 | def __init__(self, ctx: ExplorerScriptParser.Macro_callContext, compiler_ctx: CompilerCtx): 38 | super().__init__(ctx, compiler_ctx) 39 | self.arg_list_handler: ArgListCompileHandler | None = None 40 | 41 | def collect(self) -> list[SsbOperation]: 42 | name = str(self.ctx.MACRO_CALL())[1:] 43 | args: list[SsbOpParam] = [] 44 | if self.arg_list_handler: 45 | args = self.arg_list_handler.collect() 46 | if name not in self.compiler_ctx.macros.keys(): 47 | raise SsbCompilerError(f(_("Macro {name} not found."))) 48 | macro = self.compiler_ctx.macros[name] 49 | 50 | self.compiler_ctx.source_map_builder.next_macro_opcode_called_in( 51 | None, self.ctx.start.line - 1, self.ctx.start.charPositionInLine 52 | ) 53 | return macro.build( 54 | self.compiler_ctx.counter_ops, 55 | self.compiler_ctx.counter_labels, 56 | dict(zip(macro.variables, args)), 57 | self.compiler_ctx.source_map_builder, 58 | ) 59 | 60 | def add(self, obj: ArgListCompileHandler) -> None: 61 | if isinstance(obj, ArgListCompileHandler): 62 | self.arg_list_handler = obj 63 | return 64 | self._raise_add_error(obj) 65 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/compiler/label_jump_to_remover.py: -------------------------------------------------------------------------------- 1 | """ 2 | Opposite of decompiler.label_jump_to_resolver -> Removes LabelJumps and Labels 3 | and replaces jumps by regular opcodes arguments. 4 | """ 5 | 6 | # MIT License 7 | # 8 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 9 | # 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | # 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | # 28 | from __future__ import annotations 29 | 30 | import logging 31 | 32 | from explorerscript.error import SsbCompilerError 33 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 34 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabelJump, SsbLabel 35 | from explorerscript.util import f, _ 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | 40 | class OpsLabelJumpToRemover: 41 | def __init__(self, routines: list[list[SsbOperation]], label_offsets: dict[int, int]): 42 | logger.debug("Removing labels - replacing them with opcode jumps...") 43 | self.routines: list[list[SsbOperation]] = [] 44 | 45 | # label_offsets is a dict that maps label ids to their next opcode offset id 46 | for routine_id, rtn in enumerate(routines): 47 | new_rtn_ops: list[SsbOperation] = [] 48 | self.routines.append(new_rtn_ops) 49 | for op in rtn: 50 | if isinstance(op, SsbLabelJump): 51 | # Remove the jump and add the label offset as last argument 52 | new_op = op.root 53 | assert op.label is not None 54 | if op.label.id not in label_offsets: 55 | label_id = op.label.original_name 56 | if label_id is None: 57 | label_id = f"" 58 | raise SsbCompilerError( 59 | f(_("Label {label_id} does not exist, but a jump to it does (remove it).")) 60 | ) 61 | new_op.params.append(label_offsets[op.label.id]) 62 | new_rtn_ops.append(new_op) 63 | elif isinstance(op, SsbLabel): 64 | # Remove 65 | pass 66 | else: 67 | new_rtn_ops.append(op) 68 | -------------------------------------------------------------------------------- /explorerscript/ssb_converting/decompiler/write_handler_manager.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2020-2025 Capypara and the SkyTemple Contributors 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # 23 | from __future__ import annotations 24 | 25 | import logging 26 | from typing import TYPE_CHECKING 27 | 28 | from igraph import Vertex 29 | 30 | from explorerscript.ssb_converting.decompiler.write_handlers.abstract import AbstractWriteHandler 31 | from explorerscript.ssb_converting.ssb_data_types import SsbOperation 32 | from explorerscript.ssb_converting.ssb_special_ops import SsbLabel, SsbForeignLabel, SsbLabelJump 33 | 34 | logger = logging.getLogger(__name__) 35 | 36 | if TYPE_CHECKING: 37 | from explorerscript.ssb_converting.ssb_decompiler import ExplorerScriptSsbDecompiler 38 | 39 | 40 | class WriteHandlerManager: 41 | """Class that retrieves the handlers for vertices in a ExplorerScript graph.""" 42 | 43 | @classmethod 44 | def get_for( 45 | cls, 46 | v: Vertex, 47 | decompiler: ExplorerScriptSsbDecompiler, 48 | parent: AbstractWriteHandler, 49 | vertex_that_started_block: Vertex | None, 50 | is_first_vertex_of_block: bool, 51 | ) -> AbstractWriteHandler: 52 | from explorerscript.ssb_converting.decompiler.write_handlers.foreign_label import ForeignLabelWriteHandler 53 | from explorerscript.ssb_converting.decompiler.write_handlers.label import LabelWriteHandler 54 | from explorerscript.ssb_converting.decompiler.write_handlers.label_jump import LabelJumpWriteHandler 55 | from explorerscript.ssb_converting.decompiler.write_handlers.simple_op import SimpleOperationWriteHandler 56 | 57 | if "op" not in v.attributes(): 58 | raise ValueError(f"Invalid Ssb vertex: {v}") 59 | op: SsbOperation = v["op"] 60 | if isinstance(op, SsbLabel): 61 | return LabelWriteHandler(v, decompiler, parent, vertex_that_started_block, is_first_vertex_of_block) 62 | if isinstance(op, SsbForeignLabel): 63 | return ForeignLabelWriteHandler(v, decompiler, parent, vertex_that_started_block, is_first_vertex_of_block) 64 | if isinstance(op, SsbLabelJump): 65 | return LabelJumpWriteHandler(v, decompiler, parent) 66 | return SimpleOperationWriteHandler(v, decompiler, parent) 67 | --------------------------------------------------------------------------------