diff --git a/.all-contributorsrc b/.all-contributorsrc index 44068f0..4599aa6 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -66,6 +66,6 @@ "skipCi": true, "repoType": "github", "repoHost": "https://github.com", - "projectName": "roblox-pyc", + "projectName": "roblox-py", "projectOwner": "AsynchronousAI" } diff --git a/.argon.project.json b/.argon.project.json new file mode 100644 index 0000000..7688d03 --- /dev/null +++ b/.argon.project.json @@ -0,0 +1,53 @@ +{ + "name": "Argon", + "tree": { + "$className": "DataModel", + "Chat": { + "$path": "src/Chat" + }, + "Lighting": { + "$path": "src/Lighting" + }, + "LocalizationService": { + "$path": "src/LocalizationService" + }, + "ReplicatedFirst": { + "$path": "src/ReplicatedFirst" + }, + "ReplicatedStorage": { + "$path": "src/ReplicatedStorage" + }, + "ServerScriptService": { + "$path": "src/ServerScriptService" + }, + "ServerStorage": { + "$path": "src/ServerStorage" + }, + "SoundService": { + "$path": "src/SoundService" + }, + "StarterGui": { + "$path": "src/StarterGui" + }, + "StarterPack": { + "$path": "src/StarterPack" + }, + "StarterPlayer": { + "StarterCharacterScripts": { + "$path": "src/StarterPlayer/StarterCharacterScripts" + }, + "StarterPlayerScripts": { + "$path": "src/StarterPlayer/StarterPlayerScripts" + } + }, + "Teams": { + "$path": "src/Teams" + }, + "TestService": { + "$path": "src/TestService" + }, + "Workspace": { + "$path": "src/Workspace" + } + } +} \ No newline at end of file diff --git "a/.gitbook/assets/Screenshot 2023-07-10 at 12.06.03\342\200\257AM.png" "b/.gitbook/assets/Screenshot 2023-07-10 at 12.06.03\342\200\257AM.png" deleted file mode 100644 index 0ee1c46..0000000 Binary files "a/.gitbook/assets/Screenshot 2023-07-10 at 12.06.03\342\200\257AM.png" and /dev/null differ diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml deleted file mode 100644 index e5483e5..0000000 --- a/.github/workflows/python-publish.yml +++ /dev/null @@ -1,40 +0,0 @@ -# This workflow will upload a Python Package using Twine when a release is created -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -name: Upload Python Package - -on: - push: - paths: - - setup.cfg - -permissions: - contents: read - -jobs: - deploy: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v3 - with: - python-version: '3.x' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install build - - name: Build package - run: python -m build - - name: Publish package - uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/sponsors.yml b/.github/workflows/sponsors.yml deleted file mode 100644 index 7629e17..0000000 --- a/.github/workflows/sponsors.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Generate Sponsors README -on: - workflow_dispatch: - schedule: - - cron: 30 15 * * 0-6 -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - name: Checkout 🛎️ - uses: actions/checkout@v2 - - - name: Generate Sponsors 💖 - uses: JamesIves/github-sponsors-readme-action@v1 - with: - token: ${{ secrets.PAT }} - file: 'README.md' - - - name: Deploy to GitHub Pages 🚀 - uses: JamesIves/github-pages-deploy-action@v4 - with: - branch: main - folder: '.' diff --git a/.gitignore b/.gitignore index 7e99e36..7fe03c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,13 @@ -*.pyc \ No newline at end of file +# idrk +*.pyc + +# Cobalt preprocessed and compiled +*.cii +*.byte + +test.py +test.lua + +# Build +/build +/dist \ No newline at end of file diff --git a/COPYRIGHTS.txt b/COPYRIGHTS.md similarity index 99% rename from COPYRIGHTS.txt rename to COPYRIGHTS.md index a6bc8c1..f616149 100644 --- a/COPYRIGHTS.txt +++ b/COPYRIGHTS.md @@ -1,4 +1,4 @@ -Pythonlua: +# Pythonlua: Apache License Version 2.0, January 2004 @@ -202,7 +202,7 @@ Pythonlua: See the License for the specific language governing permissions and limitations under the License. -TextBoxPlus and Highlighter (used in roblox plugin): +# TextBoxPlus and Highlighter (used in roblox plugin): MIT License diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index c3e3f04..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -recursive-include robloxpyc *.pkl -recursive-include robloxpyc *.lua -recursive-include robloxpyc *.ts \ No newline at end of file diff --git a/README.md b/README.md index a6b4e62..5b64519 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Introduction + +> **NOTICE:** +> This is the indev build [![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-) @@ -10,6 +13,7 @@ ## Sponsors 0 sadly + ## Contributors @@ -46,63 +50,9 @@ *** -``` -pip install roblox-pyc -``` - - - -Python, Lunar, C, C++ Compiler for Roblox. - -Python 3.13 (dev), C (all versions), C++ (all versions), Lunar -> Lua(u) - -> This has NO RELATION with .pyc files, roblox-py, or roblox-ts - -> C/C++ is still in progress. - -> Python is fully implemented, all code should work because it supports the dev build of Python 3.13. - -*** - -### Features - -* 🔄 **Interchangeable**\ - roblox-pyc supports using Lua, Lunar, roblox-ts, C, C++, and Python all at once so you can have the best of all sides. -* ☄️ **Ultrafast compiler**\ - The roblox-pyc compiler is designed so entire projects can be compiled in a matter of seconds -* 📉 **Optimized code**\ - roblox-pyc is a source-source compiler, it doesn't use any WASM or anything like that to cheat its way and has major performance drops. It uses an AST and rewrites your code and optimizes it. -* ⚠️ **Easy error checking**\ - Your code can easily be checked for errors because of the precompiler error system. -* 🧩 **Cross-language module support**\ - roblox-pyc allows you to require/import modules from other languages. -* 🛠️ **Supports everything**\ - Regardless if you use Rojo, Argon, in Mac, Windows with any code editors or anything else roblox-pyc is highly customizable and allows you to use any of them -* ↗️ **Customizable**\ - You can customize roblox-pyc to change your C/C++ version or dynamic library or any QoL features, not only that roblox-pyc and all of its dependencies are open-source so you can mod it and change anything to your liking -* 💻 **Languages**\ - roblox-pyc supports a great variety of languages that are fully programmed. -* 🌎 **Upload your code to the world**\ - Using a VScode sync plugin you can upload your code to the world with GitHub, GitLab, whatever. -* 📲 **In-roblox plugin**\ - If you dont what to use VScode, python supports a roblox plugin which can be hosted in the terminal with all the features listed above! -* 🌙 **Lunar**\ - roblox-pyc comes with a custom language called lunar with amazing syntax features and an extended standard library, which is a modified version of MoonScript for roblox - -*** -## Unsupported features -- Import * (python) -- Syntax based slicing (python) (workaround: use slice builtin function) -- C/C++ (not implemented yet) -- _\_slots_\_ (python) (adding soon) -- _\_dict_\_ (python) (adding soon) -*** - -### Credits +Python, C, C++ Compiler for Roblox. -* [Highlighter](https://github.com/boatbomber/Highlighter). modified to work with python (plugin usage) -* [TextBoxPlus](https://github.com/boatbomber/TextBoxPlus). uses a modified version with autocomplete (plugin usage) -* [pythonlua](https://github.com/dmitrii-eremin/python-lua). this is heavily modified version with flask implementation and compiler changes. (read licenses in [copyright.txt](COPYRIGHTS.txt)) -* [seasnake](https://github.com/pybee/seasnake) and sealang. Modified to convert C/C++ to Luau rather than C/C++ to Python 2.7 -* [MoonScript](https://github.com/leafo/moonscript). Modified to work with the Roblox API (Lunar). -* [LuauAST](). roblox-pyc uses roblox-ts's LuauAST to generate Luau code. (not used in current versions) +## Building +- `pip install pyinstaller` +- `pyinstaller src/rbxpy.py` +*** \ No newline at end of file diff --git a/build.md b/build.md deleted file mode 100644 index 67382e9..0000000 --- a/build.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: For personal usage so I can remember what commands to use. ---- - -# Technical Guide - -## Build - -* `python3 -m build` -* `pip install dist/roblox_pyc-{version}-py3-none-any.whl --force-reinstall` - -## Config - -* open setup.cfg -* change version - -## Upload - -GitHub actions does this whenever a commit is passed on `setup.cfg.` - -* `twine upload dist/*` diff --git a/c-docs/introduction.md b/c-docs/introduction.md deleted file mode 100644 index 11466a3..0000000 --- a/c-docs/introduction.md +++ /dev/null @@ -1,52 +0,0 @@ -# Introduction - -> These languages are best for learning new syntax - -## C - -``` -rbxc c -``` - -Replaces all Lua scripts with C and comments old code. - -``` -rbxc w -``` - -Compile all C scripts, when enter is clicked again in the terminal compile again. - -``` -rbxc lib -``` - -Download the library, Recommended to install in the VsCode equivalent of ReplicatedStorage with the filename, for example, it is src/shared/roblox-pyc.lua in Rojo. - - - -## C++ - -``` -rbxcpp c -``` - -Replaces all Lua scripts with C++ and comments old code. - -``` -rbxcpp w -``` - -Compile all C++ scripts, when enter is clicked again in the terminal compile again. - -``` -rbxcpp lib -``` - -Download the library, Recommended to install in the VsCode equivalent of ReplicatedStorage with the filename, for example, it is src/shared/roblox-pyc.lua in Rojo. - - - -> The recommended C and C++ docs are by `devdocs.io` and are highly recommended - - - diff --git a/cli-docs/introduction.md b/cli-docs/introduction.md deleted file mode 100644 index b10767e..0000000 --- a/cli-docs/introduction.md +++ /dev/null @@ -1,39 +0,0 @@ -# Introduction - -## Commands - -The CLI is accessible by using - -``` -rpyc -``` - -it has the commands - -* config | Open config menu -* devforum | Open devforum post in your browser -* discord | Open the discord server in your browser -* github | Open the github page in your browser - -Everything else will open the help guide. - - - -*** - -``` -rpyc config -rpyc devforum -rpyc discord -rpyc github -``` - -## Config - -Configuration allows you to modify roblox-pyc and is **REQUIRED** for C and C++ to give it the - -std, stdlib, dynamiclib. - - - -Using the config command will give you options on which languages you want to modify, then some more individual settings. diff --git a/cli/installation.md b/cli/installation.md deleted file mode 100644 index 921f38d..0000000 --- a/cli/installation.md +++ /dev/null @@ -1,33 +0,0 @@ -# Installation - -### Install - -``` -pip install roblox-pyc -``` - -### Installed CLIs - -The following CLI's will be installed to your device - -#### Main compiler - -(You can use one of the equivalents also) - -* rbxpy | Python compiler -* rbxc | C compiler -* rbxcpp | C++ compiler -* rbxlun | Lunar compiler - -#### Primary tools - -* roblox-pyc | Primary tool, includes config and help -* rpyc | Same as roblox-pyc -* rblx-pyc | Same as roblox-pyc - -#### Equivalents - -* rblx-lun | Same as roblox-lunar -* rblx-py | Same as roblox-py -* rblx-c | Same as roblox-c -* rblx-cp | Same as roblox-cpp diff --git a/docs/404.html b/docs/404.html deleted file mode 100644 index 2687156..0000000 --- a/docs/404.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - -

404

- - \ No newline at end of file diff --git a/docs/c.html b/docs/c.html deleted file mode 100644 index 1d6f72e..0000000 --- a/docs/c.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - -

C and C++ are not available to the public

- - \ No newline at end of file diff --git a/docs/cpp.html b/docs/cpp.html deleted file mode 100644 index 1d6f72e..0000000 --- a/docs/cpp.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - -

C and C++ are not available to the public

- - \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index b408e3c..0000000 --- a/docs/index.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - -

roblox-pyc playground

-
- - -
- - - \ No newline at end of file diff --git a/docs/moonscript.html b/docs/moonscript.html deleted file mode 100644 index b0faf3f..0000000 --- a/docs/moonscript.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - roblox-pyc playground - - - - - - - - - - - - -

roblox-pyc playground

- -
- -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/moonscript.js b/docs/moonscript.js deleted file mode 100644 index d498f33..0000000 --- a/docs/moonscript.js +++ /dev/null @@ -1,213 +0,0 @@ -CodeMirror.defineMode("moonscript", function(config, parserConfig) { - var moonKeywords = parserConfig.keywords || {}; - var moonBuiltins = parserConfig.builtins || {}; - var moonAtoms = parserConfig.atoms || {}; - - var indentUnit = config.indentUnit; - - function prefixRE(words) { - return new RegExp("^(?:" + words.join("|") + ")\\b"); - } - - function wordRE(words) { - return new RegExp("^(?:" + words.join("|") + "))\\b"); - } - - var keywords = prefixRE(Object.keys(moonKeywords)); - var builtins = prefixRE(Object.keys(moonBuiltins)); - var atoms = wordRE(Object.keys(moonAtoms)); - - var indentStack = []; - - function tokenBase(stream, state) { - var ch = stream.next(); - - if (ch === "-" && stream.eat("-")) { - stream.skipToEnd(); - return "comment"; - } - - if (ch === "\"" || ch === "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } - - if (ch === "[" && stream.match("[")) { - state.tokenize = tokenLongString(); - return state.tokenize(stream, state); - } - - if (/\d/.test(ch)) { - stream.eatWhile(/[\w\.]/); - return "number"; - } - - if (ch === ".") { - if (stream.eat(".")) { - if (stream.eat(".")) { - return "operator"; - } - return "punctuation"; - } - return "punctuation"; - } - - if (ch === "=") { - if (stream.eat("=")) { - return "operator"; - } - return "punctuation"; - } - - if (ch === "<" || ch === ">") { - if (stream.eat("=")) { - return "operator"; - } - return "operator"; - } - - if (ch === "~") { - if (stream.eat("=")) { - return "operator"; - } - return "punctuation"; - } - - if (ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%" || ch === "^") { - return "operator"; - } - - if (ch === "#" || ch === "@" || ch === "$" || ch === "&" || ch === "`") { - return "punctuation"; - } - - if (ch === "{" || ch === "}" || ch === "(" || ch === ")" || ch === "[" || ch === "]") { - return "bracket"; - } - - if (ch === ";" || ch === ",") { - return "punctuation"; - } - - if (/\w/.test(ch)) { - stream.eatWhile(/\w/); - var cur = stream.current(); - if (keywords.test(cur)) { - return "keyword"; - } - if (builtins.test(cur)) { - return "builtin"; - } - if (atoms.test(cur)) { - return "atom"; - } - return "variable"; - } - - return null; - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false; - var next; - while ((next = stream.next()) != null) { - if (next === quote && !escaped) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && next === "\\"; - } - return "string"; - }; - } - - function tokenLongString() { - return function(stream, state) { - var bracketCount = 0; - var next; - while ((next = stream.next()) != null) { - if (next === "]" && bracketCount === 2) { - state.tokenize = tokenBase; - break; - } - if (next === "]") { - bracketCount++; - } else { - bracketCount = 0; - } - } - return "string"; - }; - } - - function pushIndent(state, indent) { - state.indent.push(indent); - } - - function popIndent(state) { - state.indent.pop(); - } - - function topIndent(state) { - return state.indent[state.indent.length - 1]; - } - - return { - startState: function() { - return { - tokenize: tokenBase, - indent: [] - }; - }, - - token: function(stream, state) { - if (stream.eatSpace()) { - return null; - } - var style = state.tokenize(stream, state); - var currentIndent = topIndent(state); - if (style === "keyword" && stream.current() === "do") { - pushIndent(state, currentIndent + indentUnit); - } - if (style === "bracket" && stream.current() === "{") { - pushIndent(state, currentIndent + indentUnit); - } - if (style === "bracket" && stream.current() === "}") { - popIndent(state); - } - return style; - }, - - indent: function(state, textAfter) { - if (state.tokenize !== tokenBase) { - return null; - } - var currentIndent = topIndent(state); - if (/^\s*[\{\[]/.test(textAfter)) { - return currentIndent; - } - if (/^\s*\}/.test(textAfter)) { - if (state.indent.length > 1) { - return state.indent[state.indent.length - 2]; - } - return 0; - } - if (/^\s*else/.test(textAfter)) { - return currentIndent; - } - if (/^\s*end/.test(textAfter)) { - if (state.indent.length > 1) { - return state.indent[state.indent.length - 2]; - } - return 0; - } - return currentIndent; - }, - - lineComment: "--", - fold: "brace" - }; - }); - - CodeMirror.defineMIME("text/x-moonscript", "moonscript"); \ No newline at end of file diff --git a/docs/python.html b/docs/python.html deleted file mode 100644 index fbe2aef..0000000 --- a/docs/python.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - roblox-pyc playground - - - - - - - - - - - - -

roblox-pyc playground

- -
- -
- -
- -
- - - - \ No newline at end of file diff --git a/lunar-docs/introduction.md b/lunar-docs/introduction.md deleted file mode 100644 index fc3fb88..0000000 --- a/lunar-docs/introduction.md +++ /dev/null @@ -1,27 +0,0 @@ -# Introduction - -> This language is best for production use and great syntax sugar - -``` -rbxlun c -``` - -Replaces all Lua scripts with lunar and comments old code. - -``` -rbxlun w -``` - -Compile all lunar scripts, when enter is clicked again in the terminal compile again. - -``` -rbxlun lib -``` - -Starts dependencies installation - - - -> Lunar is based on MoonScript but modified for Roblox. -> -> The official docs page for Lunar will redirect you to the official moonscript docs. diff --git a/lunar/api.md b/lunar/api.md deleted file mode 100644 index c53307f..0000000 --- a/lunar/api.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -description: How can you use the built in API. ---- - -# API - -Lunar is pretty much Moonscript apart from the roblox classes. Thats it! diff --git a/py-docs/introduction.md b/py-docs/introduction.md deleted file mode 100644 index 2ef8364..0000000 --- a/py-docs/introduction.md +++ /dev/null @@ -1,29 +0,0 @@ -# Introduction - -> This language is best for a very functional and easy language. - -``` -rbxpy c -``` - -Replaces all Lua scripts with Python and comments old code. - -``` -rbxpy p -``` - -Start the plugin server (Python only). - -``` -rbxpy w -``` - -Compile all Python scripts, when enter is clicked again in the terminal compile again. - -``` -rbxpy lib -``` - -Starts dependencies installation - -> The official docs page for python will redirect you to the Python 3.13 docs diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 5f8f5e3..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build-system] -build-backend = "setuptools.build_meta" -requires = ["setuptools", "wheel"] \ No newline at end of file diff --git a/python/api.md b/python/api.md deleted file mode 100644 index 293eb63..0000000 --- a/python/api.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -description: How can you use the built in API. ---- - -# API - -## Built-in - -Use the - -``` -game -``` - -variable to access the game in python, This is literarily the game variable in roblox. - -
ValidPlayers = [
-    "builderman"
-]
-
-@py.Workspace.Spawn.Touched
-def onTouch(touch):
-    print("Spawn has been touched by", touch.Name)
-    
-@game.Players.PlayerAdded
-def onPlrAdd(plr):
-    if plr.Name in ValidPlayers:
-        # The player is in our admin list, print admin joined
-        print("Admin", plr.Name, "has joined the game!!")
-        
-
- -The above code will do the following: - -* When a part in workspace called "Spawn" is touched print the touching parts name in the output -* When a player joins and their name is in the ValidPlayers list that means they are a admin and output that - -Compiled code: - -This code generated may be outdated, code generated with newer versions of roblox-pyc should deliver better results -```lua ---// Compiled using roblox-pyc \-- - - ------------------------------------- BUILT IN ------------------------------- -local py, libs, builtin = unpack(require(game.ReplicatedStorage["roblox.pyc"])(script).py) - -local stringmeta = builtin.stringmeta -local list = builtin.list -local str = builtin.str -local id = builtin.id -local int = builtin.int -local operator_in = builtin.operator_in -local min = builtin.min - ------------------------------------------------------------------------------ -local ValidPlayers = list {stringmeta "builderman"} -local function onTouch(touch) - print(stringmeta "Spawn has been touched by", touch.Name) -end -onTouch = py.Workspace.Spawn.Touched(onTouch) -local function onPlrAdd(plr) - if (operator_in(plr.Name, ValidPlayers)) then - print(stringmeta "Admin", plr.Name, stringmeta "has joined the game!!") - end -end -onPlrAdd = py.Players.PlayerAdded(onPlrAdd) -``` - -> stringmeta, list, dict are all functions used to add the Python API to lua objects. - -*** - -## Embedding lua - -Sometimes you need to do something in Lua, inside of a python script! But how? - -```python -print("Python code") -for i in range(1,10): - print("Python loop", i) -``` - -Thats python code, now let's add some lua code - -```psl -print("Python code") -for i in range(10): - print("Python loop", i) - -"""[[lua]] -``` - -```lua --- As seen above this is not a multiline comment because of the [[lua]] -for i = 1, 10 do - print(i) -end - --- We can still use python functions in lua this time without a problem -for i, v in range(10) do - print(i) -end -``` - -```python -""" -``` - -> This is the same script but I split it to 3 different code blocks for syntax highlighting - - - -*** - -Check out the tests in GitHub! diff --git a/rbxpy.spec b/rbxpy.spec new file mode 100644 index 0000000..75eb2a2 --- /dev/null +++ b/rbxpy.spec @@ -0,0 +1,43 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['src/rbxpy.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='rbxpy', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) +coll = COLLECT( + exe, + a.binaries, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='rbxpy', +) diff --git a/robloxpyc/LuauAST/README.md b/robloxpyc/LuauAST/README.md deleted file mode 100644 index 24c5105..0000000 --- a/robloxpyc/LuauAST/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# roblox-ts LuauAST - -## Structure - -**index.ts** - re-exports all exported values in each file - -**types/enums.ts** - enums for luau.SyntaxKind, luau.BinaryOperator, luau.UnaryOperator - -**types/nodes.ts** - contains interfaces that describe each node - -**impl/mapping.ts** - contains interfaces to describe the mapping of each node to IndexableExpression, Expression, Statement, and Field - -**impl/create.ts** - helper functions for creating nodes - -**impl/traversal.ts** - helper functions for traversing nodes - -**impl/typeGuards.ts** - helper functions for determining what a particular node is - -**impl/List.ts** - types + helper functions for luau.List and luau.ListNode - -## Adding a new node - -In order to add a new type of node, you must add a new: - -1. enum to luau.SyntaxKind in enums.ts -2. interface to nodes.ts that describes the node -3. field in mapping.ts for what kind of node it is -4. typeGuard using makeGuard in typeGuards.ts AND add to specific generic guard Set diff --git a/robloxpyc/LuauAST/bundle.ts b/robloxpyc/LuauAST/bundle.ts deleted file mode 100644 index 84fe503..0000000 --- a/robloxpyc/LuauAST/bundle.ts +++ /dev/null @@ -1,22 +0,0 @@ -// types -export * from "../LuauAST/types/mapping"; -export * from "../LuauAST/types/nodes"; -export * from "../LuauAST/types/operators"; - -// impls -export * from "../LuauAST/impl/create"; -export * from "../LuauAST/impl/enums"; -export * from "../LuauAST/impl/List"; -export * from "../LuauAST/impl/typeGuards"; - -// util -export * from "../LuauAST/util/getKindName"; -export * from "../LuauAST/util/isMetamethod"; -export * from "../LuauAST/util/isReservedClassField"; -export * from "../LuauAST/util/isReservedIdentifier"; -export * from "../LuauAST/util/isValidIdentifier"; -export * from "../LuauAST/util/isValidNumberLiteral"; - -// depends on above files -export * from "../LuauAST/impl/globals"; -export * from "../LuauAST/impl/strings"; diff --git a/robloxpyc/LuauAST/impl/List.ts b/robloxpyc/LuauAST/impl/List.ts deleted file mode 100644 index 39bb3d4..0000000 --- a/robloxpyc/LuauAST/impl/List.ts +++ /dev/null @@ -1,212 +0,0 @@ -import luau from "../../LuauAST"; -import { assert } from "../../LuauAST/util/assert"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unnecessary-type-constraint -export type NoInfer = [A][A extends any ? 0 : never]; - -const LIST_MARKER = Symbol("List"); - -export type ListNode = { - prev?: luau.ListNode; - next?: luau.ListNode; - value: T; -}; - -export type List = { - [LIST_MARKER]: true; - head?: luau.ListNode; - tail?: luau.ListNode; - readonly: boolean; -}; - -export namespace list { - // list creation functions - - export function makeNode(value: T): luau.ListNode { - assert(luau.isNode(value)); - return { value }; - } - - export function make(...values: Array): luau.List { - assert(values.every(node => luau.isNode(node))); - if (values.length > 0) { - const head = luau.list.makeNode(values[0]); - let tail = head; - for (let i = 1; i < values.length; i++) { - const node = luau.list.makeNode(values[i]); - tail.next = node; - node.prev = tail; - tail = node; - } - return { [LIST_MARKER]: true, head, tail, readonly: false }; - } else { - return { [LIST_MARKER]: true, readonly: false }; - } - } - - // type guard - - export function isList(value: unknown): value is luau.List { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return typeof value === "object" && (value as any)[LIST_MARKER] === true; - } - - // list utility functions - - export function clone(list: luau.List): luau.List { - const newList = luau.list.make(); - luau.list.forEach(list, element => { - luau.list.push(newList, { ...element }); - }); - return newList; - } - - export function push(list: luau.List, value: NoInfer) { - assert(luau.isNode(value)); - assert(!list.readonly); - const node = luau.list.makeNode(value); - if (list.tail) { - list.tail.next = node; - node.prev = list.tail; - } else { - list.head = node; - } - list.tail = node; - } - - export function pushList(list: luau.List, other: luau.List) { - assert(!list.readonly); - assert(!other.readonly); - other.readonly = true; - - if (other.head && other.tail) { - if (list.head && list.tail) { - list.tail.next = other.head; - other.head.prev = list.tail; - list.tail = other.tail; - } else { - list.head = other.head; - list.tail = other.tail; - } - } - } - - export function shift(list: luau.List): T | undefined { - assert(!list.readonly); - if (list.head) { - const head = list.head; - if (head.next) { - list.head = head.next; - head.next.prev = undefined; - } else { - list.tail = undefined; - list.head = undefined; - } - return head.value; - } - } - - export function unshift(list: luau.List, value: NoInfer) { - assert(luau.isNode(value)); - assert(!list.readonly); - const node = luau.list.makeNode(value); - if (list.head) { - list.head.prev = node; - node.next = list.head; - } else { - list.tail = node; - } - list.head = node; - } - - export function unshiftList(list: luau.List, other: luau.List) { - assert(!list.readonly); - assert(!other.readonly); - other.readonly = true; - - if (other.head && other.tail) { - if (list.head && list.tail) { - list.head.prev = other.tail; - other.tail.next = list.head; - list.head = other.head; - } else { - list.head = other.head; - list.tail = other.tail; - } - } - } - - export function isEmpty(list: luau.List) { - return list.head === undefined; - } - - export function isNonEmpty(list: luau.List): list is Required> { - return list.head !== undefined; - } - - export function forEach(list: luau.List, callback: (value: NoInfer) => void) { - let node = list.head; - while (node) { - callback(node.value); - node = node.next; - } - } - - export function forEachListNode( - list: luau.List, - callback: (value: luau.ListNode) => void, - ) { - let node = list.head; - while (node) { - callback(node); - node = node.next; - } - } - - export function mapToArray( - list: luau.List, - callback: (value: NoInfer) => U, - ): Array { - const result = new Array(); - luau.list.forEach(list, value => result.push(callback(value))); - return result; - } - - export function toArray(list: luau.List): Array { - const result = new Array(); - luau.list.forEach(list, value => result.push(value)); - return result; - } - - export function every(list: luau.List, callback: (value: NoInfer) => boolean) { - let node = list.head; - while (node) { - if (!callback(node.value)) { - return false; - } - node = node.next; - } - return true; - } - - export function some(list: luau.List, callback: (value: NoInfer) => boolean) { - let node = list.head; - while (node) { - if (callback(node.value)) { - return true; - } - node = node.next; - } - return false; - } - - export function size(list: luau.List) { - let size = 0; - let node = list.head; - while (node) { - size++; - node = node.next; - } - return size; - } -} diff --git a/robloxpyc/LuauAST/impl/create.ts b/robloxpyc/LuauAST/impl/create.ts deleted file mode 100644 index a3f3f01..0000000 --- a/robloxpyc/LuauAST/impl/create.ts +++ /dev/null @@ -1,184 +0,0 @@ -// must import bundle explicitly to get `luau.create()` calls importing correctly -import * as luau from "../../LuauAST/bundle"; - -type AllowedFieldTypes = luau.BaseNode | luau.List | boolean | number | string | undefined; -type FilterProps = { [K in keyof T]: T[K] extends U ? T[K] : never }; -type FilteredNodeByKind = FilterProps; - -// creation -export function create( - kind: T, - fields: { - [K in Exclude, keyof luau.Node>]: FilteredNodeByKind[K]; - }, -): luau.NodeByKind[T] { - // super hack! - const node = Object.assign({ kind }, fields) as unknown as luau.NodeByKind[T]; - - for (const [key, value] of Object.entries(fields)) { - if (luau.isNode(value)) { - if (value.parent) { - const clone: luau.Node = { ...value }; - clone.parent = node; - node[key as never] = clone as never; - } else { - value.parent = node; - } - } else if (luau.list.isList(value)) { - luau.list.forEachListNode(value, listNode => { - if (listNode.value.parent) { - const clone: luau.Node = { ...listNode.value }; - clone.parent = node; - listNode.value = clone; - } else { - listNode.value.parent = node; - } - }); - } - } - - return node; -} - -let lastTempId = 0; - -/** - * Creates a new temporary identifier for a node. - */ -export function tempId(name = "") { - return luau.create(luau.SyntaxKind.TemporaryIdentifier, { name, id: lastTempId++ }); -} - -/** - * Creates a new `None` node. - */ -export function none() { - return luau.create(luau.SyntaxKind.None, {}); -} - -/** - * Creates a new `nil` literal node. - */ -export function nil() { - return luau.create(luau.SyntaxKind.NilLiteral, {}); -} - -/** - * Creates a new `boolean` literal node. - * @param value The value of the boolean literal. - */ -export function bool(value: boolean) { - if (value) { - return luau.create(luau.SyntaxKind.TrueLiteral, {}); - } else { - return luau.create(luau.SyntaxKind.FalseLiteral, {}); - } -} - -/** - * Creates a new `number` literal node. - * @param value The number to make - */ -export function number(value: number): luau.Expression { - if (value >= 0) { - return luau.create(luau.SyntaxKind.NumberLiteral, { value: String(value) }); - } else { - return luau.create(luau.SyntaxKind.UnaryExpression, { - operator: "-", - expression: luau.number(Math.abs(value)), - }); - } -} - -/** - * Creates a new `string` literal node. - * @param value The value of the string - */ -export function string(value: string) { - return luau.create(luau.SyntaxKind.StringLiteral, { value }); -} - -/** - * Creates a new identifier node. - * @param name The name of the identifier. - */ -export function id(name: string) { - return luau.create(luau.SyntaxKind.Identifier, { name }); -} - -/** - * Creates a new comment node. - * @param text The text of the comment - */ -export function comment(text: string) { - return luau.create(luau.SyntaxKind.Comment, { text }); -} - -/** - * Creates a new array node. - * @param members The `luau.Expression` nodes of the new array. - */ -export function array(members: Array = []) { - return luau.create(luau.SyntaxKind.Array, { - members: luau.list.make(...members), - }); -} - -/** - * Creates a new set node. - * @param members The `luau.Expression` nodes of the new set. - */ -export function set(members: Array = []) { - return luau.create(luau.SyntaxKind.Set, { - members: luau.list.make(...members), - }); -} - -/** - * Creates a new map node. - * @param fields The array of key-value mappings. - */ -export function map(fields: Array<[luau.Expression, luau.Expression]> = []) { - return luau.create(luau.SyntaxKind.Map, { - fields: luau.list.make( - ...fields.map(([index, value]) => luau.create(luau.SyntaxKind.MapField, { index, value })), - ), - }); -} - -/** - * Creates a new mixed table node. - * @param fields The array of either value or key-value mappings. - */ -export function mixedTable(fields: Array = []) { - return luau.create(luau.SyntaxKind.MixedTable, { - fields: luau.list.make( - ...fields.map(field => { - if (Array.isArray(field)) { - return luau.create(luau.SyntaxKind.MapField, { index: field[0], value: field[1] }); - } else { - return field; - } - }), - ), - }); -} - -export function binary(left: luau.Expression, operator: luau.BinaryOperator, right: luau.Expression) { - return luau.create(luau.SyntaxKind.BinaryExpression, { left, operator, right }); -} - -export function unary(operator: luau.UnaryOperator, expression: luau.Expression) { - return luau.create(luau.SyntaxKind.UnaryExpression, { operator, expression }); -} - -export function property(expression: luau.IndexableExpression, name: string) { - return luau.create(luau.SyntaxKind.PropertyAccessExpression, { expression, name }); -} - -export function call(expression: luau.IndexableExpression, args: Array = []) { - return luau.create(luau.SyntaxKind.CallExpression, { - expression, - args: luau.list.make(...args), - }); -} diff --git a/robloxpyc/LuauAST/impl/enums.ts b/robloxpyc/LuauAST/impl/enums.ts deleted file mode 100644 index aa03e25..0000000 --- a/robloxpyc/LuauAST/impl/enums.ts +++ /dev/null @@ -1,57 +0,0 @@ -export enum SyntaxKind { - // indexable expressions - Identifier, - TemporaryIdentifier, - ComputedIndexExpression, - PropertyAccessExpression, - CallExpression, - MethodCallExpression, - ParenthesizedExpression, - - // expressions - None, - NilLiteral, - FalseLiteral, - TrueLiteral, - NumberLiteral, - StringLiteral, - VarArgsLiteral, - FunctionExpression, - BinaryExpression, - UnaryExpression, - IfExpression, - Array, - Map, - Set, - MixedTable, - - // statements - Assignment, - BreakStatement, - CallStatement, - ContinueStatement, - DoStatement, - WhileStatement, - RepeatStatement, - IfStatement, - NumericForStatement, - ForStatement, - FunctionDeclaration, - MethodDeclaration, - VariableDeclaration, - ReturnStatement, - Comment, - - // fields - MapField, - - // used to detect what category a given kind falls into - FirstIndexableExpression = Identifier, - LastIndexableExpression = ParenthesizedExpression, - FirstExpression = Identifier, - LastExpression = Set, - FirstStatement = Assignment, - LastStatement = Comment, - FirstField = MapField, - LastField = MapField, -} diff --git a/robloxpyc/LuauAST/impl/globals.ts b/robloxpyc/LuauAST/impl/globals.ts deleted file mode 100644 index ce68d3d..0000000 --- a/robloxpyc/LuauAST/impl/globals.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as luau from "../../LuauAST/bundle"; - -const COROUTINE_ID = luau.id("coroutine"); -const MATH_ID = luau.id("math"); -const STRING_ID = luau.id("string"); -const TABLE_ID = luau.id("table"); -const UTF8_ID = luau.id("utf8"); - -export const globals = { - _G: luau.id("_G"), - TS: luau.id("TS"), - assert: luau.id("assert"), - bit32: luau.id("bit32"), - coroutine: { - yield: luau.property(COROUTINE_ID, "yield"), - }, - error: luau.id("error"), - exports: luau.id("exports"), - getmetatable: luau.id("getmetatable"), - ipairs: luau.id("ipairs"), - next: luau.id("next"), - pairs: luau.id("pairs"), - pcall: luau.id("pcall"), - require: luau.id("require"), - script: luau.id("script"), - select: luau.id("select"), - self: luau.id("self"), - setmetatable: luau.id("setmetatable"), - string: { - byte: luau.property(STRING_ID, "byte"), - find: luau.property(STRING_ID, "find"), - format: luau.property(STRING_ID, "format"), - gmatch: luau.property(STRING_ID, "gmatch"), - gsub: luau.property(STRING_ID, "gsub"), - lower: luau.property(STRING_ID, "lower"), - match: luau.property(STRING_ID, "match"), - rep: luau.property(STRING_ID, "rep"), - reverse: luau.property(STRING_ID, "reverse"), - split: luau.property(STRING_ID, "split"), - sub: luau.property(STRING_ID, "sub"), - upper: luau.property(STRING_ID, "upper"), - }, - super: luau.id("super"), - table: { - clear: luau.property(TABLE_ID, "clear"), - concat: luau.property(TABLE_ID, "concat"), - create: luau.property(TABLE_ID, "create"), - find: luau.property(TABLE_ID, "find"), - insert: luau.property(TABLE_ID, "insert"), - move: luau.property(TABLE_ID, "move"), - remove: luau.property(TABLE_ID, "remove"), - sort: luau.property(TABLE_ID, "sort"), - }, - utf8: { - charpattern: luau.property(UTF8_ID, "charpattern"), - codes: luau.property(UTF8_ID, "codes"), - }, - math: { - min: luau.property(MATH_ID, "min"), - }, - tostring: luau.id("tostring"), - type: luau.id("type"), - typeof: luau.id("typeof"), - unpack: luau.id("unpack"), - - // roblox - game: luau.id("game"), -}; diff --git a/robloxpyc/LuauAST/impl/strings.ts b/robloxpyc/LuauAST/impl/strings.ts deleted file mode 100644 index 95bfcf6..0000000 --- a/robloxpyc/LuauAST/impl/strings.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as luau from "../../LuauAST/bundle"; - -export const strings = { - // metamethods - __index: luau.string("__index"), - __tostring: luau.string("__tostring"), - __mode: luau.string("__mode"), - k: luau.string("k"), // used for __mode - - // types - number: luau.string("number"), - table: luau.string("table"), - - // opcall - success: luau.string("success"), - value: luau.string("value"), - error: luau.string("error"), - - // other - ", ": luau.string(", "), // used for ReadonlyArray.join() -}; diff --git a/robloxpyc/LuauAST/impl/typeGuards.ts b/robloxpyc/LuauAST/impl/typeGuards.ts deleted file mode 100644 index 767bd3c..0000000 --- a/robloxpyc/LuauAST/impl/typeGuards.ts +++ /dev/null @@ -1,144 +0,0 @@ -// must import bundle explicitly to get SyntaxKind importing correctly -import * as luau from "../../LuauAST/bundle"; - -function makeGuard(...kinds: [...Array]) { - const set = new Set(kinds); - return (node: luau.Node): node is luau.NodeByKind[T] => set.has(node.kind); -} - -// indexable expressions -export const isAnyIdentifier = makeGuard(luau.SyntaxKind.Identifier, luau.SyntaxKind.TemporaryIdentifier); -export const isIdentifier = makeGuard(luau.SyntaxKind.Identifier); -export const isTemporaryIdentifier = makeGuard(luau.SyntaxKind.TemporaryIdentifier); -export const isComputedIndexExpression = makeGuard(luau.SyntaxKind.ComputedIndexExpression); -export const isPropertyAccessExpression = makeGuard(luau.SyntaxKind.PropertyAccessExpression); -export const isCallExpression = makeGuard(luau.SyntaxKind.CallExpression); -export const isMethodCallExpression = makeGuard(luau.SyntaxKind.MethodCallExpression); -export const isParenthesizedExpression = makeGuard(luau.SyntaxKind.ParenthesizedExpression); - -export function isIndexableExpression(node: luau.Node): node is luau.IndexableExpression { - return ( - node.kind >= luau.SyntaxKind.FirstIndexableExpression && node.kind <= luau.SyntaxKind.LastIndexableExpression - ); -} - -// expressions -export const isNone = makeGuard(luau.SyntaxKind.None); -export const isNilLiteral = makeGuard(luau.SyntaxKind.NilLiteral); -export const isFalseLiteral = makeGuard(luau.SyntaxKind.FalseLiteral); -export const isTrueLiteral = makeGuard(luau.SyntaxKind.TrueLiteral); -export const isNumberLiteral = makeGuard(luau.SyntaxKind.NumberLiteral); -export const isStringLiteral = makeGuard(luau.SyntaxKind.StringLiteral); -export const isVarArgsLiteral = makeGuard(luau.SyntaxKind.VarArgsLiteral); -export const isFunctionExpression = makeGuard(luau.SyntaxKind.FunctionExpression); -export const isBinaryExpression = makeGuard(luau.SyntaxKind.BinaryExpression); -export const isUnaryExpression = makeGuard(luau.SyntaxKind.UnaryExpression); -export const isIfExpression = makeGuard(luau.SyntaxKind.IfExpression); -export const isArray = makeGuard(luau.SyntaxKind.Array); -export const isMap = makeGuard(luau.SyntaxKind.Map); -export const isSet = makeGuard(luau.SyntaxKind.Set); -export const isMixedTable = makeGuard(luau.SyntaxKind.MixedTable); - -export function isExpression(node: luau.Node): node is luau.Expression { - return node.kind >= luau.SyntaxKind.FirstExpression && node.kind <= luau.SyntaxKind.LastExpression; -} - -// statements -export const isAssignment = makeGuard(luau.SyntaxKind.Assignment); -export const isBreakStatement = makeGuard(luau.SyntaxKind.BreakStatement); -export const isCallStatement = makeGuard(luau.SyntaxKind.CallStatement); -export const isContinueStatement = makeGuard(luau.SyntaxKind.ContinueStatement); -export const isDoStatement = makeGuard(luau.SyntaxKind.DoStatement); -export const isWhileStatement = makeGuard(luau.SyntaxKind.WhileStatement); -export const isRepeatStatement = makeGuard(luau.SyntaxKind.RepeatStatement); -export const isIfStatement = makeGuard(luau.SyntaxKind.IfStatement); -export const isNumericForStatement = makeGuard(luau.SyntaxKind.NumericForStatement); -export const isForStatement = makeGuard(luau.SyntaxKind.ForStatement); -export const isFunctionDeclaration = makeGuard(luau.SyntaxKind.FunctionDeclaration); -export const isMethodDeclaration = makeGuard(luau.SyntaxKind.MethodDeclaration); -export const isVariableDeclaration = makeGuard(luau.SyntaxKind.VariableDeclaration); -export const isReturnStatement = makeGuard(luau.SyntaxKind.ReturnStatement); -export const isComment = makeGuard(luau.SyntaxKind.Comment); - -export function isStatement(node: luau.Node): node is luau.Statement { - return node.kind >= luau.SyntaxKind.FirstStatement && node.kind <= luau.SyntaxKind.LastStatement; -} - -// fields -export const isMapField = makeGuard(luau.SyntaxKind.MapField); - -export function isField(node: luau.Node): node is luau.Field { - return node.kind >= luau.SyntaxKind.FirstField && node.kind <= luau.SyntaxKind.LastField; -} - -export function isNode(value: unknown): value is luau.Node { - if (typeof value === "object" && value !== null && "kind" in value) { - // hack - const { kind } = value as { kind: unknown }; - return ( - typeof kind === "number" && - kind >= luau.SyntaxKind.FirstIndexableExpression && - kind <= luau.SyntaxKind.LastField - ); - } - return false; -} - -export const isSimple = makeGuard( - luau.SyntaxKind.Identifier, - luau.SyntaxKind.TemporaryIdentifier, - luau.SyntaxKind.NilLiteral, - luau.SyntaxKind.TrueLiteral, - luau.SyntaxKind.FalseLiteral, - luau.SyntaxKind.NumberLiteral, - luau.SyntaxKind.StringLiteral, -); - -export const isSimplePrimitive = makeGuard( - luau.SyntaxKind.NilLiteral, - luau.SyntaxKind.TrueLiteral, - luau.SyntaxKind.FalseLiteral, - luau.SyntaxKind.NumberLiteral, - luau.SyntaxKind.StringLiteral, -); - -export const isTable = makeGuard(luau.SyntaxKind.Array, luau.SyntaxKind.Set, luau.SyntaxKind.Map); - -export const isFinalStatement = makeGuard( - luau.SyntaxKind.BreakStatement, - luau.SyntaxKind.ReturnStatement, - luau.SyntaxKind.ContinueStatement, -); - -export const isCall = makeGuard(luau.SyntaxKind.CallExpression, luau.SyntaxKind.MethodCallExpression); - -export const isWritableExpression: (node: luau.Node) => node is luau.WritableExpression = makeGuard( - luau.SyntaxKind.Identifier, - luau.SyntaxKind.TemporaryIdentifier, - luau.SyntaxKind.PropertyAccessExpression, - luau.SyntaxKind.ComputedIndexExpression, -); - -export const isFunctionLike = makeGuard( - luau.SyntaxKind.FunctionDeclaration, - luau.SyntaxKind.FunctionExpression, - luau.SyntaxKind.MethodDeclaration, -); - -export const hasStatements = makeGuard( - luau.SyntaxKind.ForStatement, - luau.SyntaxKind.NumericForStatement, - luau.SyntaxKind.FunctionExpression, - luau.SyntaxKind.DoStatement, - luau.SyntaxKind.FunctionDeclaration, - luau.SyntaxKind.IfStatement, - luau.SyntaxKind.MethodDeclaration, - luau.SyntaxKind.RepeatStatement, - luau.SyntaxKind.WhileStatement, -); - -export const isExpressionWithPrecedence = makeGuard( - luau.SyntaxKind.IfExpression, - luau.SyntaxKind.UnaryExpression, - luau.SyntaxKind.BinaryExpression, -); diff --git a/robloxpyc/LuauAST/index.ts b/robloxpyc/LuauAST/index.ts deleted file mode 100644 index 8c5c762..0000000 --- a/robloxpyc/LuauAST/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import * as luau from "../LuauAST/bundle"; -export default luau; - -export * from "../LuauRenderer"; diff --git a/robloxpyc/LuauAST/types/mapping.ts b/robloxpyc/LuauAST/types/mapping.ts deleted file mode 100644 index f509d29..0000000 --- a/robloxpyc/LuauAST/types/mapping.ts +++ /dev/null @@ -1,71 +0,0 @@ -import luau from "../../LuauAST"; - -export interface IndexableExpressionByKind { - [luau.SyntaxKind.None]: luau.None; - [luau.SyntaxKind.Identifier]: luau.Identifier; - [luau.SyntaxKind.TemporaryIdentifier]: luau.TemporaryIdentifier; - [luau.SyntaxKind.ComputedIndexExpression]: luau.ComputedIndexExpression; - [luau.SyntaxKind.PropertyAccessExpression]: luau.PropertyAccessExpression; - [luau.SyntaxKind.CallExpression]: luau.CallExpression; - [luau.SyntaxKind.MethodCallExpression]: luau.MethodCallExpression; - [luau.SyntaxKind.ParenthesizedExpression]: luau.ParenthesizedExpression; -} - -export interface ExpressionByKind extends IndexableExpressionByKind { - [luau.SyntaxKind.NilLiteral]: luau.NilLiteral; - [luau.SyntaxKind.FalseLiteral]: luau.FalseLiteral; - [luau.SyntaxKind.TrueLiteral]: luau.TrueLiteral; - [luau.SyntaxKind.NumberLiteral]: luau.NumberLiteral; - [luau.SyntaxKind.StringLiteral]: luau.StringLiteral; - [luau.SyntaxKind.VarArgsLiteral]: luau.VarArgsLiteral; - [luau.SyntaxKind.FunctionExpression]: luau.FunctionExpression; - [luau.SyntaxKind.BinaryExpression]: luau.BinaryExpression; - [luau.SyntaxKind.UnaryExpression]: luau.UnaryExpression; - [luau.SyntaxKind.IfExpression]: luau.IfExpression; - [luau.SyntaxKind.Array]: luau.Array; - [luau.SyntaxKind.Map]: luau.Map; - [luau.SyntaxKind.Set]: luau.Set; - [luau.SyntaxKind.MixedTable]: luau.MixedTable; -} - -export interface StatementByKind { - [luau.SyntaxKind.Assignment]: luau.Assignment; - [luau.SyntaxKind.BreakStatement]: luau.BreakStatement; - [luau.SyntaxKind.CallStatement]: luau.CallStatement; - [luau.SyntaxKind.ContinueStatement]: luau.ContinueStatement; - [luau.SyntaxKind.DoStatement]: luau.DoStatement; - [luau.SyntaxKind.WhileStatement]: luau.WhileStatement; - [luau.SyntaxKind.RepeatStatement]: luau.RepeatStatement; - [luau.SyntaxKind.IfStatement]: luau.IfStatement; - [luau.SyntaxKind.NumericForStatement]: luau.NumericForStatement; - [luau.SyntaxKind.ForStatement]: luau.ForStatement; - [luau.SyntaxKind.FunctionDeclaration]: luau.FunctionDeclaration; - [luau.SyntaxKind.MethodDeclaration]: luau.MethodDeclaration; - [luau.SyntaxKind.VariableDeclaration]: luau.VariableDeclaration; - [luau.SyntaxKind.ReturnStatement]: luau.ReturnStatement; - [luau.SyntaxKind.Comment]: luau.Comment; -} - -export interface FieldByKind { - [luau.SyntaxKind.MapField]: luau.MapField; -} - -export interface NodeByKind extends luau.ExpressionByKind, luau.StatementByKind, luau.FieldByKind {} - -export type IndexableExpression = { - [K in keyof IndexableExpressionByKind]: IndexableExpressionByKind[K]["kind"] extends T - ? IndexableExpressionByKind[K] - : never; -}[keyof IndexableExpressionByKind]; -export type Expression = { - [K in keyof ExpressionByKind]: ExpressionByKind[K]["kind"] extends T ? ExpressionByKind[K] : never; -}[keyof ExpressionByKind]; -export type Statement = { - [K in keyof StatementByKind]: StatementByKind[K]["kind"] extends T ? StatementByKind[K] : never; -}[keyof StatementByKind]; -export type Field = { - [K in keyof FieldByKind]: FieldByKind[K]["kind"] extends T ? FieldByKind[K] : never; -}[keyof FieldByKind]; -export type Node = { - [K in keyof NodeByKind]: NodeByKind[K]["kind"] extends T ? NodeByKind[K] : never; -}[keyof NodeByKind]; diff --git a/robloxpyc/LuauAST/types/nodes.ts b/robloxpyc/LuauAST/types/nodes.ts deleted file mode 100644 index b4a778f..0000000 --- a/robloxpyc/LuauAST/types/nodes.ts +++ /dev/null @@ -1,209 +0,0 @@ -import luau from "../../LuauAST"; - -// base types -export interface BaseNode { - kind: T; - parent?: luau.Node; -} - -export interface BaseIndexableExpression< - T extends keyof luau.IndexableExpressionByKind = keyof luau.IndexableExpressionByKind, -> extends luau.BaseNode {} - -export interface BaseExpression - extends luau.BaseNode {} - -export interface BaseStatement - extends luau.BaseNode {} - -export interface BaseField extends luau.BaseNode {} - -export interface HasParameters { - parameters: luau.List; - hasDotDotDot: boolean; -} - -export type AnyIdentifier = luau.Identifier | luau.TemporaryIdentifier; - -export type WritableExpression = luau.AnyIdentifier | luau.PropertyAccessExpression | luau.ComputedIndexExpression; - -export type SimpleTypes = - | luau.Identifier - | luau.TemporaryIdentifier - | luau.NilLiteral - | luau.TrueLiteral - | luau.FalseLiteral - | luau.NumberLiteral - | luau.StringLiteral; - -export type ExpressionWithPrecedence = luau.IfExpression | luau.UnaryExpression | luau.BinaryExpression; - -// expressions -export interface None extends luau.BaseExpression {} - -export interface NilLiteral extends luau.BaseExpression {} - -export interface FalseLiteral extends luau.BaseExpression {} - -export interface TrueLiteral extends luau.BaseExpression {} - -export interface NumberLiteral extends luau.BaseExpression { - value: string; -} - -export interface StringLiteral extends luau.BaseExpression { - value: string; -} - -export interface VarArgsLiteral extends luau.BaseExpression {} - -export interface FunctionExpression extends luau.BaseExpression, HasParameters { - statements: luau.List; -} - -export interface Identifier extends luau.BaseExpression { - name: string; -} - -export interface TemporaryIdentifier extends luau.BaseExpression { - name: string; - id: number; -} - -export interface ComputedIndexExpression extends luau.BaseExpression { - expression: luau.IndexableExpression; - index: luau.Expression; -} - -export interface PropertyAccessExpression extends luau.BaseExpression { - expression: luau.IndexableExpression; - name: string; -} - -export interface CallExpression extends luau.BaseExpression { - expression: luau.IndexableExpression; - args: luau.List; -} - -export interface MethodCallExpression extends luau.BaseExpression { - name: string; - expression: luau.IndexableExpression; - args: luau.List; -} - -export interface ParenthesizedExpression extends luau.BaseExpression { - expression: luau.Expression; -} - -export interface BinaryExpression extends luau.BaseExpression { - left: luau.Expression; - operator: luau.BinaryOperator; - right: luau.Expression; -} - -export interface UnaryExpression extends luau.BaseExpression { - operator: luau.UnaryOperator; - expression: luau.Expression; -} - -export interface IfExpression extends luau.BaseExpression { - condition: luau.Expression; - expression: luau.Expression; - alternative: luau.Expression; -} - -export interface Array extends luau.BaseExpression { - members: luau.List; -} - -export interface Map extends luau.BaseExpression { - fields: luau.List; -} - -export interface Set extends luau.BaseExpression { - members: luau.List; -} - -export interface MixedTable extends luau.BaseExpression { - fields: luau.List; -} - -// statements -export interface Assignment extends luau.BaseStatement { - left: luau.WritableExpression | luau.List; - operator: luau.AssignmentOperator; - right: luau.Expression | luau.List; -} - -export interface BreakStatement extends luau.BaseStatement {} - -export interface CallStatement extends luau.BaseStatement { - expression: luau.CallExpression | luau.MethodCallExpression; -} - -export interface ContinueStatement extends luau.BaseStatement {} - -export interface DoStatement extends luau.BaseStatement { - statements: luau.List; -} - -export interface WhileStatement extends luau.BaseStatement { - condition: luau.Expression; - statements: luau.List; -} - -export interface RepeatStatement extends luau.BaseStatement { - condition: luau.Expression; - statements: luau.List; -} - -export interface IfStatement extends luau.BaseStatement { - condition: luau.Expression; - statements: luau.List; - elseBody: luau.IfStatement | luau.List; -} - -export interface NumericForStatement extends luau.BaseStatement { - id: luau.AnyIdentifier; - start: luau.Expression; - end: luau.Expression; - step?: luau.Expression; - statements: luau.List; -} - -export interface ForStatement extends luau.BaseStatement { - ids: luau.List; - expression: luau.Expression; - statements: luau.List; -} - -export interface FunctionDeclaration extends luau.BaseStatement, HasParameters { - localize: boolean; - name: luau.AnyIdentifier | luau.PropertyAccessExpression; - statements: luau.List; -} - -export interface MethodDeclaration extends luau.BaseStatement, HasParameters { - expression: luau.IndexableExpression; - name: string; - statements: luau.List; -} - -export interface VariableDeclaration extends luau.BaseStatement { - left: luau.AnyIdentifier | luau.List; - right: luau.Expression | luau.List | undefined; -} - -export interface ReturnStatement extends luau.BaseStatement { - expression: luau.Expression | luau.List; -} - -export interface Comment extends luau.BaseStatement { - text: string; -} - -// fields -export interface MapField extends luau.BaseField { - index: luau.Expression; - value: luau.Expression; -} diff --git a/robloxpyc/LuauAST/types/operators.ts b/robloxpyc/LuauAST/types/operators.ts deleted file mode 100644 index 74cc513..0000000 --- a/robloxpyc/LuauAST/types/operators.ts +++ /dev/null @@ -1,20 +0,0 @@ -export type BinaryOperator = - | "+" - | "-" - | "*" - | "/" - | "^" - | "%" - | ".." - | "<" - | "<=" - | ">" - | ">=" - | "==" - | "~=" - | "and" - | "or"; - -export type UnaryOperator = "-" | "not" | "#"; - -export type AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "..="; diff --git a/robloxpyc/LuauAST/util/assert.ts b/robloxpyc/LuauAST/util/assert.ts deleted file mode 100644 index e44225f..0000000 --- a/robloxpyc/LuauAST/util/assert.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Asserts the truthiness of `value`, stops the debugger on failure. - * @param value The value to check the truthiness of - * @param message Optional. The message of the error - */ -export function assert(value: unknown, message?: string): asserts value; -export function assert(value: false, message?: string): never; -export function assert(value: unknown, message?: string): asserts value { - /* istanbul ignore if */ - if (!value) { - debugger; - throw new Error( - `Assertion Failed! ${message ?? ""}` + - "\nThis is a compiler bug! Please submit a bug report here:" + - "\nhttps://github.com/roblox-ts/roblox-ts/issues", - ); - } -} diff --git a/robloxpyc/LuauAST/util/getKindName.ts b/robloxpyc/LuauAST/util/getKindName.ts deleted file mode 100644 index 4d4ae7a..0000000 --- a/robloxpyc/LuauAST/util/getKindName.ts +++ /dev/null @@ -1,12 +0,0 @@ -import luau from "../../LuauAST"; - -export function getKindName(kind: luau.SyntaxKind) { - // avoid FirstExpression, LastExpression, etc. - if (kind === luau.SyntaxKind.Identifier) return "Identifier"; - else if (kind === luau.SyntaxKind.ParenthesizedExpression) return "ParenthesizedExpression"; - else if (kind === luau.SyntaxKind.Set) return "Set"; - else if (kind === luau.SyntaxKind.Assignment) return "Assignment"; - else if (kind === luau.SyntaxKind.Comment) return "Comment"; - else if (kind === luau.SyntaxKind.MapField) return "MapField"; - return luau.SyntaxKind[kind]; -} diff --git a/robloxpyc/LuauAST/util/isMetamethod.ts b/robloxpyc/LuauAST/util/isMetamethod.ts deleted file mode 100644 index f2f0bd3..0000000 --- a/robloxpyc/LuauAST/util/isMetamethod.ts +++ /dev/null @@ -1,26 +0,0 @@ -const LUAU_METAMETHODS = new Set([ - "__index", - "__newindex", - "__call", - "__concat", - "__unm", - "__add", - "__sub", - "__mul", - "__div", - "__mod", - "__pow", - "__tostring", - "__metatable", - "__eq", - "__lt", - "__le", - "__mode", - "__gc", - "__len", -]); - -/** Returns true if the given string is a valid Luau metamethod */ -export function isMetamethod(id: string) { - return LUAU_METAMETHODS.has(id); -} diff --git a/robloxpyc/LuauAST/util/isReservedClassField.ts b/robloxpyc/LuauAST/util/isReservedClassField.ts deleted file mode 100644 index 5872bf1..0000000 --- a/robloxpyc/LuauAST/util/isReservedClassField.ts +++ /dev/null @@ -1,11 +0,0 @@ -const LUAU_RESERVED_CLASS_FIELDS = new Set(["__index", "new"]); - -export function isReservedClassField(id: string) { - return LUAU_RESERVED_CLASS_FIELDS.has(id); -} - -const ROACT_RESERVED_CLASS_FIELDS = new Set(["init"]); - -export function isReservedRoactClassField(id: string) { - return ROACT_RESERVED_CLASS_FIELDS.has(id); -} diff --git a/robloxpyc/LuauAST/util/isReservedIdentifier.ts b/robloxpyc/LuauAST/util/isReservedIdentifier.ts deleted file mode 100644 index 85441d4..0000000 --- a/robloxpyc/LuauAST/util/isReservedIdentifier.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { globals } from "../../LuauAST/impl/globals"; - -export function isReservedIdentifier(id: string) { - return id in globals; -} diff --git a/robloxpyc/LuauAST/util/isValidIdentifier.ts b/robloxpyc/LuauAST/util/isValidIdentifier.ts deleted file mode 100644 index a276a67..0000000 --- a/robloxpyc/LuauAST/util/isValidIdentifier.ts +++ /dev/null @@ -1,31 +0,0 @@ -// X = reserved by TypeScript -const LUAU_RESERVED_KEYWORDS = new Set([ - "and", - "break", // X - "do", // X - "else", // X - "elseif", - "end", - "false", // X - "for", // X - "function", // X - "if", // X - "in", // X - "local", - "nil", - "not", - "or", - "repeat", - "return", // X - "then", - "true", // X - "until", - "while", // X -]); - -const LUAU_IDENTIFIER_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/; - -/** Returns true if the given string is a valid Luau identifier, and does not conflict with a temporary identifier */ -export function isValidIdentifier(id: string) { - return !LUAU_RESERVED_KEYWORDS.has(id) && LUAU_IDENTIFIER_REGEX.test(id); -} diff --git a/robloxpyc/LuauAST/util/isValidNumberLiteral.ts b/robloxpyc/LuauAST/util/isValidNumberLiteral.ts deleted file mode 100644 index ebafe9e..0000000 --- a/robloxpyc/LuauAST/util/isValidNumberLiteral.ts +++ /dev/null @@ -1,7 +0,0 @@ -const DECIMAL_LITERAL_REGEX = /^(?:\d[\d_]*(?:\.[\d_]*)?|\.\d[\d_]*)(?:[eE][+-]?_*\d[\d_]*)?$/; -const BINARY_LITERAL_REGEX = /^0_*[bB]_*[01][01_]*$/; -const HEXADECIMAL_LITERAL_REGEX = /^0_*[xX]_*[\da-fA-F][\da-fA-F_]*$/; - -export function isValidNumberLiteral(text: string) { - return DECIMAL_LITERAL_REGEX.test(text) || BINARY_LITERAL_REGEX.test(text) || HEXADECIMAL_LITERAL_REGEX.test(text); -} diff --git a/robloxpyc/LuauRenderer/README.md b/robloxpyc/LuauRenderer/README.md deleted file mode 100644 index 450b3ca..0000000 --- a/robloxpyc/LuauRenderer/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# roblox-ts LuauRenderer - -This project takes a Luau AST (from LuauAST) and converts it into Luau source code in the form of a string. - -## Structure - -**index.ts** - contains the global render function, takes any node and routes it to the appropriate `renderX()` function to turn it into a string - -**RenderState.ts** - stores the current state of the render process, instance is passed into every `renderX()` function - -**nodes/** - folder containing modules that each export a `renderX(state: RenderState, node: luau.X): string` function - -**util/** - various helper modules to aid in rendering diff --git a/robloxpyc/LuauRenderer/RenderState.ts b/robloxpyc/LuauRenderer/RenderState.ts deleted file mode 100644 index 6b52f90..0000000 --- a/robloxpyc/LuauRenderer/RenderState.ts +++ /dev/null @@ -1,107 +0,0 @@ -import luau from "../LuauAST"; -import { assert } from "../LuauAST/util/assert"; -import { getEnding } from "../LuauRenderer/util/getEnding"; -import { getOrSetDefault } from "../LuauRenderer/util/getOrSetDefault"; - -const INDENT_CHARACTER = "\t"; -const INDENT_CHARACTER_LENGTH = INDENT_CHARACTER.length; - -/** - * Represents the state of a rendering process. - */ -export class RenderState { - private indent = ""; - public seenTempNodes = new Map(); - private readonly listNodesStack = new Array>(); - - /** - * Pushes an indent to the current indent level. - */ - private pushIndent() { - this.indent += INDENT_CHARACTER; - } - - /** - * Pops an indent from the current indent level. - */ - private popIndent() { - this.indent = this.indent.substr(INDENT_CHARACTER_LENGTH); - } - - private tempIdFallback = 0; - - /** - * Returns an unique identifier that is unused in the current scope. - * `this.seenTempNodes` should already be fully populated by this point! - * This is a fallback mechanism for when `solveTempIds()` does not catch something properly. - * @param node The identifier of the node - */ - public getTempName(node: luau.TemporaryIdentifier) { - const name = getOrSetDefault(this.seenTempNodes, node.id, () => `_${this.tempIdFallback++}`); - assert(name); - return name; - } - - /** - * Pushes a LuauAST node to the top of the list node stack - * @param listNode The syntax node to add to the stop of the stack. - */ - public pushListNode(listNode: luau.ListNode) { - this.listNodesStack.push(listNode); - } - - /** - * Returns the top of the scope stack. - */ - public peekListNode(): luau.ListNode | undefined { - return this.listNodesStack[this.listNodesStack.length - 1]; - } - - /** - * Pops the top list node off the syntax tree node stack. - */ - public popListNode() { - return this.listNodesStack.pop(); - } - - /** - * Adds a newline to the end of the string. - * @param text The text. - */ - public newline(text: string) { - return text + "\n"; - } - - /** - * Prefixes the text with the current indent. - * @param text The text. - */ - public indented(text: string) { - return this.indent + text; - } - - /** - * Renders a line, adding the current indent, a semicolon if necessary, and "\n". - * @param text The content of the line. - * @param endNode Node used to determine if a semicolon should be added. Undefined means no semi will be added. - */ - public line(text: string, endNode?: luau.Statement) { - let result = this.indented(text); - if (endNode) { - result += getEnding(this, endNode); - } - result = this.newline(result); - return result; - } - - /** - * Returns a rendered code block. - * @param callback The function used to render the block. - */ - public block(callback: () => T) { - this.pushIndent(); - const result = callback(); - this.popIndent(); - return result; - } -} diff --git a/robloxpyc/LuauRenderer/index.ts b/robloxpyc/LuauRenderer/index.ts deleted file mode 100644 index 2d5ab89..0000000 --- a/robloxpyc/LuauRenderer/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "../LuauRenderer/render"; -export * from "../LuauRenderer/RenderState"; -export * from "../LuauRenderer/solveTempIds"; -export * from "../LuauRenderer/util/renderStatements"; diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderCallExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderCallExpression.ts deleted file mode 100644 index 458eb3f..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderCallExpression.ts +++ /dev/null @@ -1,7 +0,0 @@ -import luau from "../../../../LuauAST"; -import { render, RenderState } from "../../../../LuauRenderer"; -import { renderArguments } from "../../../../LuauRenderer/util/renderArguments"; - -export function renderCallExpression(state: RenderState, node: luau.CallExpression) { - return `${render(state, node.expression)}(${renderArguments(state, node.args)})`; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderComputedIndexExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderComputedIndexExpression.ts deleted file mode 100644 index 1f16351..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderComputedIndexExpression.ts +++ /dev/null @@ -1,12 +0,0 @@ -import luau from "../../../../LuauAST"; -import { render, RenderState } from "../../../../LuauRenderer"; - -export function renderComputedIndexExpression(state: RenderState, node: luau.ComputedIndexExpression) { - const expStr = render(state, node.expression); - if (luau.isStringLiteral(node.index) && luau.isValidIdentifier(node.index.value)) { - return `${expStr}.${node.index.value}`; - } else { - const indexStr = render(state, node.index); - return `${expStr}[${indexStr}]`; - } -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderIdentifier.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderIdentifier.ts deleted file mode 100644 index 7250dd3..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderIdentifier.ts +++ /dev/null @@ -1,8 +0,0 @@ -import luau from "../../../../LuauAST"; -import { assert } from "../../../../LuauAST/util/assert"; -import { RenderState } from "../../../../LuauRenderer"; - -export function renderIdentifier(state: RenderState, node: luau.Identifier) { - assert(luau.isValidIdentifier(node.name), `Invalid Luau Identifier: "${node.name}"`); - return node.name; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderMethodCallExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderMethodCallExpression.ts deleted file mode 100644 index 540b63b..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderMethodCallExpression.ts +++ /dev/null @@ -1,9 +0,0 @@ -import luau from "../../../../LuauAST"; -import { assert } from "../../../../LuauAST/util/assert"; -import { render, RenderState } from "../../../../LuauRenderer"; -import { renderArguments } from "../../../../LuauRenderer/util/renderArguments"; - -export function renderMethodCallExpression(state: RenderState, node: luau.MethodCallExpression) { - assert(luau.isValidIdentifier(node.name)); - return `${render(state, node.expression)}:${node.name}(${renderArguments(state, node.args)})`; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderParenthesizedExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderParenthesizedExpression.ts deleted file mode 100644 index 7e0a8f3..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderParenthesizedExpression.ts +++ /dev/null @@ -1,15 +0,0 @@ -import luau from "../../../../LuauAST"; -import { render, RenderState } from "../../../../LuauRenderer"; - -export function renderParenthesizedExpression(state: RenderState, node: luau.ParenthesizedExpression) { - // skip nested parentheses - let expression = node.expression; - while (luau.isParenthesizedExpression(expression)) { - expression = expression.expression; - } - if (luau.isSimple(expression)) { - return render(state, node.expression); - } else { - return `(${render(state, node.expression)})`; - } -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderPropertyAccessExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderPropertyAccessExpression.ts deleted file mode 100644 index 784765a..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderPropertyAccessExpression.ts +++ /dev/null @@ -1,12 +0,0 @@ -import luau from "../../../../LuauAST"; -import { render, RenderState } from "../../../../LuauRenderer"; - -export function renderPropertyAccessExpression(state: RenderState, node: luau.PropertyAccessExpression) { - const expStr = render(state, node.expression); - const nameStr = node.name; - if (luau.isValidIdentifier(nameStr)) { - return `${expStr}.${nameStr}`; - } else { - return `${expStr}["${nameStr}"]`; - } -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderTemporaryIdentifier.ts b/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderTemporaryIdentifier.ts deleted file mode 100644 index b269e9e..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/indexable/renderTemporaryIdentifier.ts +++ /dev/null @@ -1,9 +0,0 @@ -import luau from "../../../../LuauAST"; -import { assert } from "../../../../LuauAST/util/assert"; -import { RenderState } from "../../../../LuauRenderer"; - -export function renderTemporaryIdentifier(state: RenderState, node: luau.TemporaryIdentifier) { - const name = state.getTempName(node); - assert(luau.isValidIdentifier(name), `Invalid Temporary Identifier: "${name}"`); - return name; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderArray.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderArray.ts deleted file mode 100644 index 718a4ad..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderArray.ts +++ /dev/null @@ -1,11 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderArray(state: RenderState, node: luau.Array) { - if (luau.list.isEmpty(node.members)) { - return "{}"; - } - - const membersStr = luau.list.mapToArray(node.members, member => render(state, member)).join(", "); - return `{ ${membersStr} }`; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderBinaryExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderBinaryExpression.ts deleted file mode 100644 index 75ccf2b..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderBinaryExpression.ts +++ /dev/null @@ -1,13 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { needsParentheses } from "../../../LuauRenderer/util/needsParentheses"; - -export function renderBinaryExpression(state: RenderState, node: luau.BinaryExpression) { - let result = `${render(state, node.left)} ${node.operator} ${render(state, node.right)}`; - - if (needsParentheses(node)) { - result = `(${result})`; - } - - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderFunctionExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderFunctionExpression.ts deleted file mode 100644 index a7bb2bf..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderFunctionExpression.ts +++ /dev/null @@ -1,16 +0,0 @@ -import luau from "../../../LuauAST"; -import { RenderState } from "../../../LuauRenderer"; -import { renderParameters } from "../../../LuauRenderer/util/renderParameters"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderFunctionExpression(state: RenderState, node: luau.FunctionExpression) { - if (luau.list.isEmpty(node.statements)) { - return `function(${renderParameters(state, node)}) end`; - } - - let result = ""; - result += state.newline(`function(${renderParameters(state, node)})`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.indented(`end`); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderIfExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderIfExpression.ts deleted file mode 100644 index 2eb7024..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderIfExpression.ts +++ /dev/null @@ -1,23 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { needsParentheses } from "../../../LuauRenderer/util/needsParentheses"; - -export function renderIfExpression(state: RenderState, node: luau.IfExpression) { - let result = `if ${render(state, node.condition)} then ${render(state, node.expression)} `; - - let currentAlternative = node.alternative; - while (luau.isIfExpression(currentAlternative)) { - const condition = render(state, currentAlternative.condition); - const expression = render(state, currentAlternative.expression); - result += `elseif ${condition} then ${expression} `; - currentAlternative = currentAlternative.alternative; - } - - result += `else ${render(state, currentAlternative)}`; - - if (needsParentheses(node)) { - result = `(${result})`; - } - - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderMap.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderMap.ts deleted file mode 100644 index 9584617..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderMap.ts +++ /dev/null @@ -1,15 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderMap(state: RenderState, node: luau.Map) { - if (luau.list.isEmpty(node.fields)) { - return "{}"; - } - - let result = "{\n"; - state.block(() => { - luau.list.forEach(node.fields, field => (result += state.line(`${render(state, field)},`))); - }); - result += state.indented("}"); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderMixedTable.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderMixedTable.ts deleted file mode 100644 index 1656057..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderMixedTable.ts +++ /dev/null @@ -1,16 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderMixedTable(state: RenderState, node: luau.MixedTable) { - if (luau.list.isEmpty(node.fields)) { - return "{}"; - } - - let result = "{\n"; - state.block(() => { - // temp fix for https://github.com/microsoft/TypeScript/issues/42932 - luau.list.forEach(node.fields, field => (result += state.line(`${render(state, field as luau.Node)},`))); - }); - result += state.indented("}"); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderNumberLiteral.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderNumberLiteral.ts deleted file mode 100644 index 8bac505..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderNumberLiteral.ts +++ /dev/null @@ -1,6 +0,0 @@ -import luau from "../../../LuauAST"; -import { RenderState } from "../../../LuauRenderer"; - -export function renderNumberLiteral(state: RenderState, node: luau.NumberLiteral) { - return luau.isValidNumberLiteral(node.value) ? node.value : String(Number(node.value.replace(/_/g, ""))); -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderSet.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderSet.ts deleted file mode 100644 index 218c86f..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderSet.ts +++ /dev/null @@ -1,15 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderSet(state: RenderState, node: luau.Set) { - if (luau.list.isEmpty(node.members)) { - return "{}"; - } - - let result = "{\n"; - state.block(() => { - luau.list.forEach(node.members, member => (result += state.line(`[${render(state, member)}] = true,`))); - }); - result += state.indented("}"); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderStringLiteral.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderStringLiteral.ts deleted file mode 100644 index c3a938d..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderStringLiteral.ts +++ /dev/null @@ -1,37 +0,0 @@ -import luau from "../../../LuauAST"; -import { RenderState } from "../../../LuauRenderer"; -import { getSafeBracketEquals } from "../../../LuauRenderer/util/getSafeBracketEquals"; - -function needsBracketSpacing(node: luau.StringLiteral) { - const parent = node.parent; - if (!parent) { - return false; - } - - if (luau.isMapField(parent) && node === parent.index) { - return true; - } - - if (luau.isComputedIndexExpression(parent) && node === parent.index) { - return true; - } - - if (luau.isSet(parent)) { - return true; - } - - return false; -} - -export function renderStringLiteral(state: RenderState, node: luau.StringLiteral) { - const isMultiline = node.value.includes("\n"); - if (!isMultiline && !node.value.includes('"')) { - return `"${node.value}"`; - } else if (!isMultiline && !node.value.includes("'")) { - return `'${node.value}'`; - } else { - const eqStr = getSafeBracketEquals(node.value); - const spacing = needsBracketSpacing(node) ? " " : ""; - return `${spacing}[${eqStr}[${node.value}]${eqStr}]${spacing}`; - } -} diff --git a/robloxpyc/LuauRenderer/nodes/expressions/renderUnaryExpression.ts b/robloxpyc/LuauRenderer/nodes/expressions/renderUnaryExpression.ts deleted file mode 100644 index a248607..0000000 --- a/robloxpyc/LuauRenderer/nodes/expressions/renderUnaryExpression.ts +++ /dev/null @@ -1,48 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { needsParentheses } from "../../../LuauRenderer/util/needsParentheses"; - -function needsInnerParentheses(node: luau.UnaryExpression) { - // #{} and -{} are invalid - if ((node.operator === "#" || node.operator === "-") && luau.isTable(node.expression)) { - return true; - } - - return false; -} - -function needsSpace(node: luau.UnaryExpression) { - // not always needs a space - if (node.operator === "not") { - return true; - } - - // "--" will create a comment! - if (luau.isUnaryExpression(node.expression) && node.expression.operator === "-") { - // previous expression was also "-" - return true; - } - - return false; -} - -export function renderUnaryExpression(state: RenderState, node: luau.UnaryExpression) { - let expStr = render(state, node.expression); - let opStr = node.operator; - - if (needsSpace(node)) { - opStr += " "; - } - - if (needsInnerParentheses(node)) { - expStr = `(${expStr})`; - } - - let result = `${opStr}${expStr}`; - - if (needsParentheses(node)) { - result = `(${result})`; - } - - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/fields/renderMapField.ts b/robloxpyc/LuauRenderer/nodes/fields/renderMapField.ts deleted file mode 100644 index 501243b..0000000 --- a/robloxpyc/LuauRenderer/nodes/fields/renderMapField.ts +++ /dev/null @@ -1,13 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderMapField(state: RenderState, node: luau.MapField) { - const { index, value } = node; - const valueStr = render(state, value); - if (luau.isStringLiteral(index) && luau.isValidIdentifier(index.value)) { - return `${index.value} = ${valueStr}`; - } else { - const indexStr = render(state, index); - return `[${indexStr}] = ${valueStr}`; - } -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderAssignment.ts b/robloxpyc/LuauRenderer/nodes/statements/renderAssignment.ts deleted file mode 100644 index 0bf48a7..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderAssignment.ts +++ /dev/null @@ -1,23 +0,0 @@ -import luau from "../../../LuauAST"; -import { assert } from "../../../LuauAST/util/assert"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderAssignment(state: RenderState, node: luau.Assignment) { - let leftStr: string; - if (luau.list.isList(node.left)) { - assert(!luau.list.isEmpty(node.left)); - leftStr = luau.list.mapToArray(node.left, id => render(state, id)).join(", "); - } else { - leftStr = render(state, node.left); - } - - let rightStr: string; - if (luau.list.isList(node.right)) { - assert(!luau.list.isEmpty(node.right)); - rightStr = luau.list.mapToArray(node.right, expression => render(state, expression)).join(", "); - } else { - rightStr = render(state, node.right); - } - - return state.line(`${leftStr} ${node.operator} ${rightStr}`, node); -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderBreakStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderBreakStatement.ts deleted file mode 100644 index 570b4d6..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderBreakStatement.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RenderState } from "../../../LuauRenderer"; - -export function renderBreakStatement(state: RenderState) { - return state.line(`break`); -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderCallStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderCallStatement.ts deleted file mode 100644 index f1bc938..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderCallStatement.ts +++ /dev/null @@ -1,6 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderCallStatement(state: RenderState, node: luau.CallStatement) { - return state.line(`${render(state, node.expression)}`, node); -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderComment.ts b/robloxpyc/LuauRenderer/nodes/statements/renderComment.ts deleted file mode 100644 index 30130dd..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderComment.ts +++ /dev/null @@ -1,16 +0,0 @@ -import luau from "../../../LuauAST"; -import { RenderState } from "../../../LuauRenderer"; -import { getSafeBracketEquals } from "../../../LuauRenderer/util/getSafeBracketEquals"; - -export function renderComment(state: RenderState, node: luau.Comment) { - const lines = node.text.split("\n"); - if (lines.length > 1) { - const eqStr = getSafeBracketEquals(node.text); - let result = state.line(`--[${eqStr}[`); - result += state.block(() => lines.map(line => state.line(line)).join("")); - result += state.line(`]${eqStr}]`); - return result; - } else { - return lines.map(line => state.line(`--${line}`)).join(""); - } -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderContinueStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderContinueStatement.ts deleted file mode 100644 index d983f52..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderContinueStatement.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RenderState } from "../../../LuauRenderer"; - -export function renderContinueStatement(state: RenderState) { - return state.line(`continue`); -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderDoStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderDoStatement.ts deleted file mode 100644 index c90e9c4..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderDoStatement.ts +++ /dev/null @@ -1,11 +0,0 @@ -import luau from "../../../LuauAST"; -import { RenderState } from "../../../LuauRenderer"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderDoStatement(state: RenderState, node: luau.DoStatement) { - let result = ""; - result += state.line(`do`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`end`); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderForStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderForStatement.ts deleted file mode 100644 index 4497bed..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderForStatement.ts +++ /dev/null @@ -1,15 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderForStatement(state: RenderState, node: luau.ForStatement) { - const idsStr = luau.list.mapToArray(node.ids, id => render(state, id)).join(", ") || "_"; - const expStr = render(state, node.expression); - - let result = ""; - result += state.line(`for ${idsStr} in ${expStr} do`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`end`); - - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderFunctionDeclaration.ts b/robloxpyc/LuauRenderer/nodes/statements/renderFunctionDeclaration.ts deleted file mode 100644 index 6e9baf3..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderFunctionDeclaration.ts +++ /dev/null @@ -1,19 +0,0 @@ -import luau from "../../../LuauAST"; -import { assert } from "../../../LuauAST/util/assert"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderParameters } from "../../../LuauRenderer/util/renderParameters"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderFunctionDeclaration(state: RenderState, node: luau.FunctionDeclaration) { - if (node.localize) { - assert(luau.isAnyIdentifier(node.name), "local function cannot be a property"); - } - const nameStr = render(state, node.name); - const paramStr = renderParameters(state, node); - - let result = ""; - result += state.line(`${node.localize ? "local " : ""}function ${nameStr}(${paramStr})`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`end`); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderIfStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderIfStatement.ts deleted file mode 100644 index 66dd64b..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderIfStatement.ts +++ /dev/null @@ -1,28 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderIfStatement(state: RenderState, node: luau.IfStatement) { - let result = ""; - - result += state.line(`if ${render(state, node.condition)} then`); - result += state.block(() => renderStatements(state, node.statements)); - - let currentElseBody = node.elseBody; - while (luau.isNode(currentElseBody)) { - const statements = currentElseBody.statements; - result += state.line(`elseif ${render(state, currentElseBody.condition)} then`); - result += state.block(() => renderStatements(state, statements)); - currentElseBody = currentElseBody.elseBody; - } - - if (currentElseBody && luau.list.isNonEmpty(currentElseBody)) { - result += state.line(`else`); - const statements = currentElseBody; - result += state.block(() => renderStatements(state, statements)); - } - - result += state.line(`end`); - - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderMethodDeclaration.ts b/robloxpyc/LuauRenderer/nodes/statements/renderMethodDeclaration.ts deleted file mode 100644 index 18df8e8..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderMethodDeclaration.ts +++ /dev/null @@ -1,12 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderParameters } from "../../../LuauRenderer/util/renderParameters"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderMethodDeclaration(state: RenderState, node: luau.MethodDeclaration) { - let result = ""; - result += state.line(`function ${render(state, node.expression)}:${node.name}(${renderParameters(state, node)})`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`end`); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderNumericForStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderNumericForStatement.ts deleted file mode 100644 index 68edcd5..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderNumericForStatement.ts +++ /dev/null @@ -1,24 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderNumericForStatement(state: RenderState, node: luau.NumericForStatement) { - const idStr = render(state, node.id); - const startStr = render(state, node.start); - const endStr = render(state, node.end); - - let predicateStr = `${startStr}, ${endStr}`; - - // step of 1 can be omitted - if (node.step && (!luau.isNumberLiteral(node.step) || Number(node.step.value) !== 1)) { - const stepStr = render(state, node.step); - predicateStr += `, ${stepStr}`; - } - - let result = ""; - result += state.line(`for ${idStr} = ${predicateStr} do`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`end`); - - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderRepeatStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderRepeatStatement.ts deleted file mode 100644 index bdfd0d8..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderRepeatStatement.ts +++ /dev/null @@ -1,11 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderRepeatStatement(state: RenderState, node: luau.RepeatStatement) { - let result = ""; - result += state.line(`repeat`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`until ${render(state, node.condition)}`); - return result; -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderReturnStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderReturnStatement.ts deleted file mode 100644 index 44ba2fb..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderReturnStatement.ts +++ /dev/null @@ -1,9 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderReturnStatement(state: RenderState, node: luau.ReturnStatement) { - const expStr = luau.list.isList(node.expression) - ? luau.list.mapToArray(node.expression, exp => render(state, exp)).join(", ") - : render(state, node.expression); - return state.line(`return ${expStr}`); -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderVariableDeclaration.ts b/robloxpyc/LuauRenderer/nodes/statements/renderVariableDeclaration.ts deleted file mode 100644 index 379fcd7..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderVariableDeclaration.ts +++ /dev/null @@ -1,26 +0,0 @@ -import luau from "../../../LuauAST"; -import { assert } from "../../../LuauAST/util/assert"; -import { render, RenderState } from "../../../LuauRenderer"; - -export function renderVariableDeclaration(state: RenderState, node: luau.VariableDeclaration) { - let leftStr: string; - if (luau.list.isList(node.left)) { - assert(!luau.list.isEmpty(node.left)); - leftStr = luau.list.mapToArray(node.left, id => render(state, id)).join(", "); - } else { - leftStr = render(state, node.left); - } - - if (node.right) { - let rightStr: string; - if (luau.list.isList(node.right)) { - assert(!luau.list.isEmpty(node.right)); - rightStr = luau.list.mapToArray(node.right, expression => render(state, expression)).join(", "); - } else { - rightStr = render(state, node.right); - } - return state.line(`local ${leftStr} = ${rightStr}`, node); - } else { - return state.line(`local ${leftStr}`, node); - } -} diff --git a/robloxpyc/LuauRenderer/nodes/statements/renderWhileStatement.ts b/robloxpyc/LuauRenderer/nodes/statements/renderWhileStatement.ts deleted file mode 100644 index fe87e8a..0000000 --- a/robloxpyc/LuauRenderer/nodes/statements/renderWhileStatement.ts +++ /dev/null @@ -1,11 +0,0 @@ -import luau from "../../../LuauAST"; -import { render, RenderState } from "../../../LuauRenderer"; -import { renderStatements } from "../../../LuauRenderer/util/renderStatements"; - -export function renderWhileStatement(state: RenderState, node: luau.WhileStatement) { - let result = ""; - result += state.line(`while ${render(state, node.condition)} do`); - result += state.block(() => renderStatements(state, node.statements)); - result += state.line(`end`); - return result; -} diff --git a/robloxpyc/LuauRenderer/render.ts b/robloxpyc/LuauRenderer/render.ts deleted file mode 100644 index 4d34f1b..0000000 --- a/robloxpyc/LuauRenderer/render.ts +++ /dev/null @@ -1,135 +0,0 @@ -import luau from "../LuauAST"; -import { assert } from "../LuauAST/util/assert"; -import { getKindName } from "../LuauAST/util/getKindName"; -import { renderCallExpression } from "../LuauRenderer/nodes/expressions/indexable/renderCallExpression"; -import { renderComputedIndexExpression } from "../LuauRenderer/nodes/expressions/indexable/renderComputedIndexExpression"; -import { renderIdentifier } from "../LuauRenderer/nodes/expressions/indexable/renderIdentifier"; -import { renderMethodCallExpression } from "../LuauRenderer/nodes/expressions/indexable/renderMethodCallExpression"; -import { renderParenthesizedExpression } from "../LuauRenderer/nodes/expressions/indexable/renderParenthesizedExpression"; -import { renderPropertyAccessExpression } from "../LuauRenderer/nodes/expressions/indexable/renderPropertyAccessExpression"; -import { renderTemporaryIdentifier } from "../LuauRenderer/nodes/expressions/indexable/renderTemporaryIdentifier"; -import { renderArray } from "../LuauRenderer/nodes/expressions/renderArray"; -import { renderBinaryExpression } from "../LuauRenderer/nodes/expressions/renderBinaryExpression"; -import { renderFunctionExpression } from "../LuauRenderer/nodes/expressions/renderFunctionExpression"; -import { renderIfExpression } from "../LuauRenderer/nodes/expressions/renderIfExpression"; -import { renderMap } from "../LuauRenderer/nodes/expressions/renderMap"; -import { renderMixedTable } from "../LuauRenderer/nodes/expressions/renderMixedTable"; -import { renderNumberLiteral } from "../LuauRenderer/nodes/expressions/renderNumberLiteral"; -import { renderSet } from "../LuauRenderer/nodes/expressions/renderSet"; -import { renderStringLiteral } from "../LuauRenderer/nodes/expressions/renderStringLiteral"; -import { renderUnaryExpression } from "../LuauRenderer/nodes/expressions/renderUnaryExpression"; -import { renderMapField } from "../LuauRenderer/nodes/fields/renderMapField"; -import { renderAssignment } from "../LuauRenderer/nodes/statements/renderAssignment"; -import { renderBreakStatement } from "../LuauRenderer/nodes/statements/renderBreakStatement"; -import { renderCallStatement } from "../LuauRenderer/nodes/statements/renderCallStatement"; -import { renderComment } from "../LuauRenderer/nodes/statements/renderComment"; -import { renderContinueStatement } from "../LuauRenderer/nodes/statements/renderContinueStatement"; -import { renderDoStatement } from "../LuauRenderer/nodes/statements/renderDoStatement"; -import { renderForStatement } from "../LuauRenderer/nodes/statements/renderForStatement"; -import { renderFunctionDeclaration } from "../LuauRenderer/nodes/statements/renderFunctionDeclaration"; -import { renderIfStatement } from "../LuauRenderer/nodes/statements/renderIfStatement"; -import { renderMethodDeclaration } from "../LuauRenderer/nodes/statements/renderMethodDeclaration"; -import { renderNumericForStatement } from "../LuauRenderer/nodes/statements/renderNumericForStatement"; -import { renderRepeatStatement } from "../LuauRenderer/nodes/statements/renderRepeatStatement"; -import { renderReturnStatement } from "../LuauRenderer/nodes/statements/renderReturnStatement"; -import { renderVariableDeclaration } from "../LuauRenderer/nodes/statements/renderVariableDeclaration"; -import { renderWhileStatement } from "../LuauRenderer/nodes/statements/renderWhileStatement"; -import { RenderState } from "../LuauRenderer/RenderState"; -import { solveTempIds } from "../LuauRenderer/solveTempIds"; -import { identity } from "../LuauRenderer/util/identity"; -import { renderStatements } from "../LuauRenderer/util/renderStatements"; -import { visit } from "../LuauRenderer/util/visit"; - -type Renderer = (state: RenderState, node: luau.NodeByKind[T]) => string; - -const KIND_TO_RENDERER = identity<{ [K in luau.SyntaxKind]: Renderer }>({ - // indexable expressions - [luau.SyntaxKind.Identifier]: renderIdentifier, - [luau.SyntaxKind.TemporaryIdentifier]: renderTemporaryIdentifier, - [luau.SyntaxKind.ComputedIndexExpression]: renderComputedIndexExpression, - [luau.SyntaxKind.PropertyAccessExpression]: renderPropertyAccessExpression, - [luau.SyntaxKind.CallExpression]: renderCallExpression, - [luau.SyntaxKind.MethodCallExpression]: renderMethodCallExpression, - [luau.SyntaxKind.ParenthesizedExpression]: renderParenthesizedExpression, - - // expressions - [luau.SyntaxKind.None]: () => assert(false, "Cannot render None"), - [luau.SyntaxKind.NilLiteral]: () => "nil", - [luau.SyntaxKind.FalseLiteral]: () => "false", - [luau.SyntaxKind.TrueLiteral]: () => "true", - [luau.SyntaxKind.NumberLiteral]: renderNumberLiteral, - [luau.SyntaxKind.StringLiteral]: renderStringLiteral, - [luau.SyntaxKind.VarArgsLiteral]: () => "...", - [luau.SyntaxKind.FunctionExpression]: renderFunctionExpression, - [luau.SyntaxKind.BinaryExpression]: renderBinaryExpression, - [luau.SyntaxKind.UnaryExpression]: renderUnaryExpression, - [luau.SyntaxKind.IfExpression]: renderIfExpression, - [luau.SyntaxKind.Array]: renderArray, - [luau.SyntaxKind.Map]: renderMap, - [luau.SyntaxKind.Set]: renderSet, - [luau.SyntaxKind.MixedTable]: renderMixedTable, - - // statements - [luau.SyntaxKind.Assignment]: renderAssignment, - [luau.SyntaxKind.BreakStatement]: renderBreakStatement, - [luau.SyntaxKind.CallStatement]: renderCallStatement, - [luau.SyntaxKind.ContinueStatement]: renderContinueStatement, - [luau.SyntaxKind.DoStatement]: renderDoStatement, - [luau.SyntaxKind.WhileStatement]: renderWhileStatement, - [luau.SyntaxKind.RepeatStatement]: renderRepeatStatement, - [luau.SyntaxKind.IfStatement]: renderIfStatement, - [luau.SyntaxKind.NumericForStatement]: renderNumericForStatement, - [luau.SyntaxKind.ForStatement]: renderForStatement, - [luau.SyntaxKind.FunctionDeclaration]: renderFunctionDeclaration, - [luau.SyntaxKind.MethodDeclaration]: renderMethodDeclaration, - [luau.SyntaxKind.VariableDeclaration]: renderVariableDeclaration, - [luau.SyntaxKind.ReturnStatement]: renderReturnStatement, - [luau.SyntaxKind.Comment]: renderComment, - - // fields - [luau.SyntaxKind.MapField]: renderMapField, -}); - -/** - * Returns a string that represents the given syntax node, `node`, as Luau code. - * Recursively called until the node is completely rendered. - * @param state The state of the current rendering process. - * @param node The node to render as Luau code. - */ -export function render(state: RenderState, node: luau.Node): string { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return KIND_TO_RENDERER[node.kind](state, node as any); -} - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function debugAST(ast: luau.List) { - let indent = ""; - - const pushIndent = () => (indent += "\t"); - const popIndent = () => (indent = indent.substring(1)); - - visit(ast, { - before: node => { - // eslint-disable-next-line no-console - console.log(`${indent}${getKindName(node.kind)}`); - pushIndent(); - }, - after: () => { - popIndent(); - }, - }); -} - -/** - * Returns a string that represents the given syntax tree, `ast`, as Luau code. - */ -export function renderAST(ast: luau.List): string { - const state = new RenderState(); - - solveTempIds(state, ast); - - // useful for visualizing the Luau AST structure - // debugAST(ast); - - return renderStatements(state, ast); -} diff --git a/robloxpyc/LuauRenderer/solveTempIds.ts b/robloxpyc/LuauRenderer/solveTempIds.ts deleted file mode 100644 index d8f8263..0000000 --- a/robloxpyc/LuauRenderer/solveTempIds.ts +++ /dev/null @@ -1,134 +0,0 @@ -import luau from "../LuauAST"; -import { assert } from "../LuauAST/util/assert"; -import { RenderState } from "../LuauRenderer"; -import { visit } from "../LuauRenderer/util/visit"; - -function isFullyScopedNode(node: luau.Node): boolean { - return luau.isForStatement(node) || luau.isNumericForStatement(node) || luau.isFunctionLike(node); -} - -function isScopeEdge(node: luau.Node, edge: "head" | "tail"): boolean { - if (node.parent) { - // is the first statement in a block that creates scope - if (luau.hasStatements(node.parent)) { - if (node === node.parent.statements[edge]?.value) { - return true; - } - } - - // non-list elseBody would have the elseBody itself as a parent, - // which would be a luau.IfStatement and handled above - if ( - luau.isIfStatement(node.parent) && - luau.list.isList(node.parent.elseBody) && - node === node.parent.elseBody[edge]?.value - ) { - return true; - } - } - - return false; -} - -const isScopeStart = (node: luau.Node) => isScopeEdge(node, "head"); -const isScopeEnd = (node: luau.Node) => isScopeEdge(node, "tail"); - -interface Scope { - ids: Set; - lastTry: Map; - parent?: Scope; -} - -function createScope(parent?: Scope): Scope { - return { - ids: new Set(), - lastTry: new Map(), - parent, - }; -} - -function scopeHasId(scope: Scope, id: string): boolean { - if (scope.ids.has(id)) { - return true; - } - if (scope.parent) { - return scopeHasId(scope.parent, id); - } - return false; -} - -export function solveTempIds(state: RenderState, ast: luau.List | luau.Node) { - const tempIdsToProcess = new Array(); - const nodesToScopes = new Map(); - - const scopeStack = [createScope()]; - - function pushScopeStack() { - scopeStack.push(createScope(peekScopeStack())); - } - - function popScopeStack() { - return scopeStack.pop(); - } - - function peekScopeStack() { - const scope = scopeStack[scopeStack.length - 1]; - assert(scope); - return scope; - } - - function registerId(name: string) { - peekScopeStack().ids.add(name); - } - - visit(ast, { - before: node => { - if (isFullyScopedNode(node)) pushScopeStack(); - if (isScopeStart(node)) pushScopeStack(); - - if (luau.isTemporaryIdentifier(node)) { - nodesToScopes.set(node, peekScopeStack()); - tempIdsToProcess.push(node); - } else if (luau.isVariableDeclaration(node)) { - if (luau.list.isList(node.left)) { - luau.list.forEach(node.left, node => { - if (luau.isIdentifier(node)) { - registerId(node.name); - } - }); - } else if (luau.isIdentifier(node.left)) { - registerId(node.left.name); - } - } else if (luau.isFunctionLike(node)) { - luau.list.forEach(node.parameters, node => { - if (luau.isIdentifier(node)) { - registerId(node.name); - } - }); - } - }, - after: node => { - if (isFullyScopedNode(node)) popScopeStack(); - if (isScopeEnd(node)) popScopeStack(); - }, - }); - - for (const tempId of tempIdsToProcess) { - if (state.seenTempNodes.get(tempId.id) === undefined) { - const scope = nodesToScopes.get(tempId); - assert(scope); - - const seperator = tempId.name === "" ? "" : "_"; - - let input = `_${tempId.name}`; - let i = scope.lastTry.get(input) ?? 1; - while (scopeHasId(scope, input)) { - input = `_${tempId.name}${seperator}${i++}`; - } - scope.lastTry.set(input, i); - scope.ids.add(input); - - state.seenTempNodes.set(tempId.id, input); - } - } -} diff --git a/robloxpyc/LuauRenderer/util/getEnding.ts b/robloxpyc/LuauRenderer/util/getEnding.ts deleted file mode 100644 index fb3dbbc..0000000 --- a/robloxpyc/LuauRenderer/util/getEnding.ts +++ /dev/null @@ -1,101 +0,0 @@ -import luau from "../../LuauAST"; -import { assert } from "../../LuauAST/util/assert"; -import { RenderState } from "../../LuauRenderer"; - -function endsWithIndexableExpressionInner(node: luau.Expression): boolean { - if (luau.isIndexableExpression(node)) { - // `a` or `(a)` or `a.b` or `a[b]` or `a()` - return true; - } else if (luau.isBinaryExpression(node)) { - // `a + b` - return endsWithIndexableExpressionInner(node.right); - } else if (luau.isUnaryExpression(node)) { - // `-a` - return endsWithIndexableExpressionInner(node.expression); - } else if (luau.isIfExpression(node)) { - // `if a then b else c` - // `if a then b elseif c then d else e` - return endsWithIndexableExpressionInner(node.alternative); - } - return false; -} - -function endsWithIndexableExpression(node: luau.Statement) { - if (luau.isCallStatement(node)) { - // `a()` - return true; - } else if (luau.isVariableDeclaration(node) || luau.isAssignment(node)) { - // `local a = b` or `a = b` or `local a` or `local a, b` - let furthestRight: luau.Expression; - if (node.right) { - if (luau.list.isList(node.right)) { - assert(luau.list.isNonEmpty(node.right)); - furthestRight = node.right.tail.value; - } else { - furthestRight = node.right; - } - } else if (luau.list.isList(node.left)) { - assert(luau.list.isNonEmpty(node.left)); - furthestRight = node.left.tail.value; - } else { - furthestRight = node.left; - } - return endsWithIndexableExpressionInner(furthestRight); - } - return false; -} - -function startsWithParenthesisInner(node: luau.Expression): boolean { - if (luau.isParenthesizedExpression(node)) { - // `(a)` - return true; - } else if (luau.isCall(node) || luau.isPropertyAccessExpression(node) || luau.isComputedIndexExpression(node)) { - // `(a)()` or `(a):b()` or `(a).b` or `(a)[b]` - return startsWithParenthesisInner(node.expression); - } - return false; -} - -function startsWithParenthesis(node: luau.Statement) { - if (luau.isCallStatement(node)) { - // `(a)()` - return startsWithParenthesisInner(node.expression.expression); - } else if (luau.isAssignment(node)) { - if (luau.list.isList(node.left)) { - // `(a).b, c = d` - assert(luau.list.isNonEmpty(node.left)); - return startsWithParenthesisInner(node.left.head.value); - } else { - // `(a).b = c` - return startsWithParenthesisInner(node.left); - } - } - return false; -} - -function getNextNonComment(state: RenderState) { - let listNode = state.peekListNode()?.next; - while (listNode && luau.isComment(listNode.value)) { - listNode = listNode.next; - } - return listNode?.value; -} - -/** - * Resolves if the given statement needs to end with a `;` or not. - * - * Used to avoid "ambiguous syntax" errors in Luau. - * - * This is only necessary in statements which can end in an IndexableExpression: - * - CallStatement - * - VariableDeclaration - * - Assignment - */ -export function getEnding(state: RenderState, node: luau.Statement) { - const nextStatement = getNextNonComment(state); - if (nextStatement !== undefined && endsWithIndexableExpression(node) && startsWithParenthesis(nextStatement)) { - return ";"; - } else { - return ""; - } -} diff --git a/robloxpyc/LuauRenderer/util/getOrSetDefault.ts b/robloxpyc/LuauRenderer/util/getOrSetDefault.ts deleted file mode 100644 index f94d4eb..0000000 --- a/robloxpyc/LuauRenderer/util/getOrSetDefault.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Attempts to `map.get(key)`. If the value is `undefined`, it will run `map.set(key, getDefaultValue())` and return that instead. - * @param map The map to get the value from. - * @param key A key that is possibly mapped to a value in `map`. - * @param getDefaultValue A function that returns a default value that `key` should be mapped to, if `key` is not already mapped to something. - */ -export function getOrSetDefault(map: Map, key: K, getDefaultValue: () => V) { - let value = map.get(key); - if (value === undefined) { - value = getDefaultValue(); - map.set(key, value); - } - return value; -} diff --git a/robloxpyc/LuauRenderer/util/getSafeBracketEquals.ts b/robloxpyc/LuauRenderer/util/getSafeBracketEquals.ts deleted file mode 100644 index b8d08aa..0000000 --- a/robloxpyc/LuauRenderer/util/getSafeBracketEquals.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function getSafeBracketEquals(str: string) { - let amtEquals = 0; - while (str.includes(`]${"=".repeat(amtEquals)}]`) || str.endsWith(`]${"=".repeat(amtEquals)}`)) { - amtEquals++; - } - return "=".repeat(amtEquals); -} diff --git a/robloxpyc/LuauRenderer/util/identity.ts b/robloxpyc/LuauRenderer/util/identity.ts deleted file mode 100644 index e8f9c9e..0000000 --- a/robloxpyc/LuauRenderer/util/identity.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function identity(value: T): T { - return value; -} diff --git a/robloxpyc/LuauRenderer/util/needsParentheses.ts b/robloxpyc/LuauRenderer/util/needsParentheses.ts deleted file mode 100644 index 6b258fc..0000000 --- a/robloxpyc/LuauRenderer/util/needsParentheses.ts +++ /dev/null @@ -1,65 +0,0 @@ -import luau from "../../LuauAST"; -import { assert } from "../../LuauAST/util/assert"; - -// https://www.lua.org/manual/5.1/manual.html#2.5.6 -/* - 1. or - 2. and - 3. < > <= >= ~= == - 4. .. - 5. + - - 6. * / % - 7. not # - (unary) - 8. ^ -*/ - -const IF_EXPRESSION_PRECEDENCE = 1; - -const UNARY_OPERATOR_PRECEDENCE: { [K in luau.UnaryOperator]: number } = { - not: 7, - "#": 7, - "-": 7, -}; - -const BINARY_OPERATOR_PRECEDENCE: { [K in luau.BinaryOperator]: number } = { - or: 1, - and: 2, - "<": 3, - ">": 3, - "<=": 3, - ">=": 3, - "~=": 3, - "==": 3, - "..": 4, - "+": 5, - "-": 5, - "*": 6, - "/": 6, - "%": 6, - "^": 8, -}; - -// are these all the expression types that need to be considered..? -function getPrecedence(node: luau.ExpressionWithPrecedence) { - if (luau.isIfExpression(node)) { - return IF_EXPRESSION_PRECEDENCE; - } else if (luau.isBinaryExpression(node)) { - return BINARY_OPERATOR_PRECEDENCE[node.operator]; - } else if (luau.isUnaryExpression(node)) { - return UNARY_OPERATOR_PRECEDENCE[node.operator]; - } - assert(false); -} - -export function needsParentheses(node: luau.ExpressionWithPrecedence) { - if (node.parent && luau.isExpressionWithPrecedence(node.parent)) { - const nodePrecedence = getPrecedence(node); - const parentPrecedence = getPrecedence(node.parent); - if (nodePrecedence < parentPrecedence) { - return true; - } else if (nodePrecedence === parentPrecedence) { - return luau.isBinaryExpression(node.parent) && node === node.parent.right; - } - } - return false; -} diff --git a/robloxpyc/LuauRenderer/util/renderArguments.ts b/robloxpyc/LuauRenderer/util/renderArguments.ts deleted file mode 100644 index 11473e8..0000000 --- a/robloxpyc/LuauRenderer/util/renderArguments.ts +++ /dev/null @@ -1,7 +0,0 @@ -import luau from "../../LuauAST"; -import { render, RenderState } from "../../LuauRenderer"; - -/** Renders the given list of expressions into a string separated by commas */ -export function renderArguments(state: RenderState, expressions: luau.List) { - return luau.list.mapToArray(expressions, v => render(state, v)).join(", "); -} diff --git a/robloxpyc/LuauRenderer/util/renderParameters.ts b/robloxpyc/LuauRenderer/util/renderParameters.ts deleted file mode 100644 index 9325696..0000000 --- a/robloxpyc/LuauRenderer/util/renderParameters.ts +++ /dev/null @@ -1,15 +0,0 @@ -import luau from "../../LuauAST"; -import { render, RenderState } from "../../LuauRenderer"; - -/** - * Renders the given list of identifiers inside of `node` into a string sepearted by commas - * - * Adds `...` onto the end if node.hasDotDotDot is true - */ -export function renderParameters(state: RenderState, node: luau.HasParameters) { - const paramStrs = luau.list.mapToArray(node.parameters, param => render(state, param)); - if (node.hasDotDotDot) { - paramStrs.push("..."); - } - return paramStrs.join(", "); -} diff --git a/robloxpyc/LuauRenderer/util/renderStatements.ts b/robloxpyc/LuauRenderer/util/renderStatements.ts deleted file mode 100644 index 7080948..0000000 --- a/robloxpyc/LuauRenderer/util/renderStatements.ts +++ /dev/null @@ -1,30 +0,0 @@ -import luau from "../../LuauAST"; -import { assert } from "../../LuauAST/util/assert"; -import { render, RenderState } from "../../LuauRenderer"; - -/** - * Renders the given list of statements. - * - * Pushes each listNode onto the state.listNodesStack as it gets - * rendered to give context to other statements as they render. - * Useful for getting the next or previous sibling statement. - */ -export function renderStatements(state: RenderState, statements: luau.List) { - let result = ""; - let listNode = statements.head; - let hasFinalStatement = false; - while (listNode !== undefined) { - assert( - !hasFinalStatement || luau.isComment(listNode.value), - "Cannot render statement after break, continue, or return!", - ); - hasFinalStatement ||= luau.isFinalStatement(listNode.value); - - state.pushListNode(listNode); - result += render(state, listNode.value); - state.popListNode(); - - listNode = listNode.next; - } - return result; -} diff --git a/robloxpyc/LuauRenderer/util/visit.ts b/robloxpyc/LuauRenderer/util/visit.ts deleted file mode 100644 index efd3984..0000000 --- a/robloxpyc/LuauRenderer/util/visit.ts +++ /dev/null @@ -1,162 +0,0 @@ -import luau from "../../LuauAST"; -import { identity } from "../../LuauRenderer/util/identity"; - -export interface Visitor { - before?: (node: luau.Node) => void; - after?: (node: luau.Node) => void; -} - -type VisitStrategy = (node: luau.NodeByKind[T], visitor: Visitor) => void; - -const NOOP = () => {}; - -const KIND_TO_VISITOR = identity<{ [K in luau.SyntaxKind]: VisitStrategy }>({ - // indexable expressions - [luau.SyntaxKind.Identifier]: NOOP, - [luau.SyntaxKind.TemporaryIdentifier]: NOOP, - [luau.SyntaxKind.ComputedIndexExpression]: (node, visitor) => { - visitNode(node.expression, visitor); - visitNode(node.index, visitor); - }, - [luau.SyntaxKind.PropertyAccessExpression]: (node, visitor) => visitNode(node.expression, visitor), - [luau.SyntaxKind.CallExpression]: (node, visitor) => { - visitNode(node.expression, visitor); - visitList(node.args, visitor); - }, - [luau.SyntaxKind.MethodCallExpression]: (node, visitor) => { - visitNode(node.expression, visitor); - visitList(node.args, visitor); - }, - [luau.SyntaxKind.ParenthesizedExpression]: (node, visitor) => visitNode(node.expression, visitor), - - // expressions - [luau.SyntaxKind.None]: NOOP, - [luau.SyntaxKind.NilLiteral]: NOOP, - [luau.SyntaxKind.FalseLiteral]: NOOP, - [luau.SyntaxKind.TrueLiteral]: NOOP, - [luau.SyntaxKind.NumberLiteral]: NOOP, - [luau.SyntaxKind.StringLiteral]: NOOP, - [luau.SyntaxKind.VarArgsLiteral]: NOOP, - [luau.SyntaxKind.FunctionExpression]: (node, visitor) => { - visitList(node.parameters, visitor); - visitList(node.statements, visitor); - }, - [luau.SyntaxKind.BinaryExpression]: (node, visitor) => { - visitNode(node.left, visitor); - visitNode(node.right, visitor); - }, - [luau.SyntaxKind.UnaryExpression]: (node, visitor) => visitNode(node.expression, visitor), - [luau.SyntaxKind.IfExpression]: (node, visitor) => { - visitNode(node.condition, visitor); - visitNode(node.expression, visitor); - visitNode(node.alternative, visitor); - }, - [luau.SyntaxKind.Array]: (node, visitor) => visitList(node.members, visitor), - [luau.SyntaxKind.Map]: (node, visitor) => visitList(node.fields, visitor), - [luau.SyntaxKind.Set]: (node, visitor) => visitList(node.members, visitor), - [luau.SyntaxKind.MixedTable]: (node, visitor) => visitList(node.fields, visitor), - - // statements - [luau.SyntaxKind.Assignment]: (node, visitor) => { - if (luau.list.isList(node.left)) { - visitList(node.left, visitor); - } else { - visitNode(node.left, visitor); - } - if (luau.list.isList(node.right)) { - visitList(node.right, visitor); - } else { - visitNode(node.right, visitor); - } - }, - [luau.SyntaxKind.BreakStatement]: NOOP, - [luau.SyntaxKind.CallStatement]: (node, visitor) => visitNode(node.expression, visitor), - [luau.SyntaxKind.ContinueStatement]: NOOP, - [luau.SyntaxKind.DoStatement]: (node, visitor) => visitList(node.statements, visitor), - [luau.SyntaxKind.WhileStatement]: (node, visitor) => { - visitNode(node.condition, visitor); - visitList(node.statements, visitor); - }, - [luau.SyntaxKind.RepeatStatement]: (node, visitor) => { - visitList(node.statements, visitor); - visitNode(node.condition, visitor); - }, - [luau.SyntaxKind.IfStatement]: (node, visitor) => { - visitNode(node.condition, visitor); - visitList(node.statements, visitor); - if (luau.list.isList(node.elseBody)) { - visitList(node.elseBody, visitor); - } else { - visitNode(node.elseBody, visitor); - } - }, - [luau.SyntaxKind.NumericForStatement]: (node, visitor) => { - visitNode(node.id, visitor); - visitNode(node.start, visitor); - visitNode(node.end, visitor); - if (node.step) { - visitNode(node.step, visitor); - } - visitList(node.statements, visitor); - }, - [luau.SyntaxKind.ForStatement]: (node, visitor) => { - visitList(node.ids, visitor); - visitList(node.statements, visitor); - }, - [luau.SyntaxKind.FunctionDeclaration]: (node, visitor) => { - visitNode(node.name, visitor); - visitList(node.parameters, visitor); - visitList(node.statements, visitor); - }, - [luau.SyntaxKind.MethodDeclaration]: (node, visitor) => { - visitNode(node.expression, visitor); - visitList(node.parameters, visitor); - visitList(node.statements, visitor); - }, - [luau.SyntaxKind.VariableDeclaration]: (node, visitor) => { - if (luau.list.isList(node.left)) { - visitList(node.left, visitor); - } else { - visitNode(node.left, visitor); - } - if (node.right) { - if (luau.list.isList(node.right)) { - visitList(node.right, visitor); - } else { - visitNode(node.right, visitor); - } - } - }, - [luau.SyntaxKind.ReturnStatement]: (node, visitor) => { - if (luau.list.isList(node.expression)) { - visitList(node.expression, visitor); - } else { - visitNode(node.expression, visitor); - } - }, - [luau.SyntaxKind.Comment]: NOOP, - - // fields - [luau.SyntaxKind.MapField]: (node, visitor) => { - visitNode(node.index, visitor); - visitNode(node.value, visitor); - }, -}); - -function visitNode(node: luau.Node, visitor: Visitor) { - visitor.before?.(node); - KIND_TO_VISITOR[node.kind](node as never, visitor); - visitor.after?.(node); -} - -function visitList(list: luau.List, visitor: Visitor) { - luau.list.forEach(list, v => visitNode(v, visitor)); -} - -export function visit(ast: luau.List | luau.Node, visitor: Visitor) { - if (luau.list.isList(ast)) { - visitList(ast, visitor); - } else { - visitNode(ast, visitor); - } -} diff --git a/robloxpyc/__communication__/README.md b/robloxpyc/__communication__/README.md deleted file mode 100644 index bc2de0a..0000000 --- a/robloxpyc/__communication__/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Info -This folder is to be ignored as it holds just random files used to hold configuration and bindings -between Python and TS. \ No newline at end of file diff --git a/robloxpyc/__communication__/cfg.pkl b/robloxpyc/__communication__/cfg.pkl deleted file mode 100644 index 66161e8..0000000 Binary files a/robloxpyc/__communication__/cfg.pkl and /dev/null differ diff --git a/robloxpyc/__communication__/ts.json b/robloxpyc/__communication__/ts.json deleted file mode 100644 index e69de29..0000000 diff --git a/robloxpyc/__init__.py b/robloxpyc/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/robloxpyc/basecompilers.py b/robloxpyc/basecompilers.py deleted file mode 100644 index 9c9e194..0000000 --- a/robloxpyc/basecompilers.py +++ /dev/null @@ -1,250 +0,0 @@ -import sys - -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - import pytranslator, parser, header - from errormanager import * - from configmanager import * - from util import * -else: - from . import pytranslator, parser, header - from .errormanager import * - from .configmanager import * - from .util import * - - - -def cppcompile(r, file, pluscount=False): - if file.endswith(".cpp") and os.environ.get("ENABLE_BETA_RPYC") == True: - # compile the file to a file with the same name and path but .lua - try: - newctranslator = parser.CodeConverter(file, getconfig("c", "dynamiclibpath", "None")) - newctranslator.parse( - os.path.join(r, file), - # C not C++ - flags=[ - '-I%s' % inc for inc in [] - ] + [ - '-D%s' % define for define in [] - ] + [ - '-std=%s' % getconfig("cpp", "std", "c++20") - ] + [ - '-stdlib=%s' % getconfig("cpp", "stdlib", "libc++") - ] - ) - path = os.path.join(r, file) - newctranslator.diagnostics(sys.stderr) - relative_path = backwordreplace(path,".cpp", ".lua", 1) - with open(relative_path, 'w') as out: - newctranslator.output(relative_path, out) - - #print(colortext.green("Compiled "+os.path.join(r, file))) - if pluscount: - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - except Exception as e: - if "To provide a path to libclang use Config.set_library_path() or Config.set_library_file()" in str(e): - print(error("dylib not found, use `roblox-pyc config`, c++, dynamiclibpath, and set the path to the dynamic library.")) - print(error(f"Compile Error!\n\n "+str(e), f"{os.path.join(r, file)}")) - debug("Compiler error "+str(e)) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - - return 0 - else: - print(error("C is not enabled, please enable it in the config.")) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 -def ccompile(r, file, pluscount=False): - if file.endswith(".c") and os.environ.get("ENABLE_BETA_RPYC") == True: - # compile the file to a file with the same name and path but .lua - try: - newctranslator = parser.CodeConverter(file, getconfig("c", "dynamiclibpath", "None")) - newctranslator.parse( - os.path.join(r, file), - # C not C++ - flags=[ - '-I%s' % inc for inc in [] - ] + [ - '-D%s' % define for define in [] - ] + [ - '-std=%s' % getconfig("c", "std", "c11") - ] + [ - '-stdlib=%s' % getconfig("c", "stdlib", "libc") - ] - ) - path = os.path.join(r, file) - - newctranslator.diagnostics(sys.stderr) - relative_path = backwordreplace(path,".c", ".lua", 1) - - with open(relative_path, 'w') as out: - newctranslator.output(relative_path, out) - - #print(colortext.green("Compiled "+os.path.join(r, file))) - if pluscount: - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - except Exception as e: - if "To provide a path to libclang use Config.set_library_path() or Config.set_library_file()" in str(e): - print(error("dylib not found, use `roblox-pyc config`, c, dynamiclibpath, and set the path to the dynamic library.")) - print(error(f"Compile Error!\n\n "+str(e), f"{os.path.join(r, file)}")) - debug("Compile error at "+str(e)) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 - else: - print(error("C is not enabled, please enable it in the config.")) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 -def pycompile(r, file, pluscount=False): - # compile the file to a file with the same name and path but .lua - contents = "" - - try: - with open(os.path.join(r, file)) as rf: - contents = rf.read() - except Exception as e: - print(error(f"Failed to read {os.path.join(r, file)}!\n\n "+str(e))) - # do not compile the file if it cannot be read - return - - try: - translator = pytranslator.Translator() - lua_code = translator.translate(contents) - #print(colortext.green("Compiled "+os.path.join(r, file))) - # get the relative path of the file and replace .py with .lua - path = os.path.join(r, file) - - relative_path = backwordreplace(path,".py", ".lua", 1) - - if not os.path.exists(os.path.dirname(relative_path)): - os.makedirs(os.path.dirname(relative_path)) - - with open(relative_path, "w") as f: - f.write(lua_code) - - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - except Exception as e: - print(error(f"Compile Error!\n\n "+str(e), f"{os.path.join(r, file)}")) - debug("Compile error at "+str(e)) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 -def lunarcompile(r, file, pluscount=False): - # compile the file to a file with the same name and path but .lua - # Run command and check if anything is outputted to stderr, stdout, or stdin - - process = subprocess.Popen(["moonc", os.path.join(r, file)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = process.communicate() - - if stdout or stderr: - if stdout: - print(error(f"Compile Error!\n\n "+str(stdout), f"{os.path.join(r, file)}")) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 - else: - print(error(f"Compile Error!\n\n "+str(stderr), f"{os.path.join(r, file)}")) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 - else: - try: - newheader = header.lunarheader([]) - - # check if the new file has been created - if os.path.exists(os.path.join(r, file.replace(".moon", ".lua"))): - #print(colortext.green("Compiled "+os.path.join(r, file))) - with open(os.path.join(r, file.replace(".moon", ".lua")), "r") as f: - contents = f.read() - contents = backwordreplace(contents, "return", "", 1) - - else: - print(error("File error for "+os.path.join(r, file)+"!")) - if pluscount: - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - except Exception as e: - print(error(f"Compile Error!\n\n "+str(e), f"{os.path.join(r, file)}")) - - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 -def robloxtscompile(r, file, pluscount=False): - # Just add to pluscount, add later - try: - print(warn("At the moment roblox-ts is not supported, please wait for a future update.")) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - except Exception as e: - print(error(f"Compile Error!\n\n "+str(e), f"{os.path.join(r, file)}")) - if pluscount: - #pluscount.error() - pluscount.update(1) - pluscount.current += 1 - #global count - #count += 1 - return 0 -def allcompile(r, file, pluscount): - # Checks what file it is then redirects to the correct compiler - if file.endswith(".py"): - pycompile(r, file, pluscount) - elif file.endswith(".moon"): - lunarcompile(r, file, pluscount) - elif file.endswith(".c"): - ccompile(r, file, pluscount) - elif file.endswith(".cpp"): - cppcompile(r, file, pluscount) - elif file.endswith(".ts"): - robloxtscompile(r, file, pluscount) - \ No newline at end of file diff --git a/robloxpyc/bindings.py b/robloxpyc/bindings.py deleted file mode 100644 index bf35581..0000000 --- a/robloxpyc/bindings.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Provides python bindings to LuauAST and LuauRenderer.""" -# LuauAST: /robloxpyc/LuauAST (Typescript) -# LuauRenderer: /robloxpyc/LuauRenderer (Typescript) -# Script Path /robloxpyc/bindings.py - -# @AsynchronousAI - 2023 -import subprocess - -class TypescriptBridge: - def __init__(path): - pass - #I have no idea how to do this, but I'll try to figure it out. Maybe use C and make a bridge, or use JSON files to communicate and subprocess. (Most likely). \ No newline at end of file diff --git a/robloxpyc/binopdesc.py b/robloxpyc/binopdesc.py deleted file mode 100644 index e24108c..0000000 --- a/robloxpyc/binopdesc.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Binary operation description""" -import ast - - -_DEFAULT_FORMAT = "{left} {operation} {right}" - -def addfunc(left, right): - # check if left and right have anything other than 0-9 - # left and right are name objects, so we need to get the id - if (not isinstance(left, ast.Num) or not isinstance(right, ast.Num)): - return "safeadd({left}, {right})" - else : - return "{left} + {right}" -class BinaryOperationDesc: - """Binary operation description""" - - OPERATION = { - ast.Add: { - "value": "+", - "function": addfunc - }, - ast.Sub: { - "value": "-", - "format": _DEFAULT_FORMAT, - }, - ast.Mult: { - "value": "*", - "format": _DEFAULT_FORMAT, - }, - ast.Div: { - "value": "/", - "format": _DEFAULT_FORMAT, - }, - ast.Mod: { - "value": "", - "format": "formatmod({left}, {right})", - }, - ast.Pow: { - "value": "", - "format": "math.pow({left}, {right})", - }, - ast.FloorDiv: { - "value": "/", - "format": "math.floor({left} {operation} {right})", - }, - ast.LShift: { - "value": "", - "format": "bit32.lshift({left}, {right})", - }, - ast.RShift: { - "value": "", - "format": "bit32.rshift({left}, {right})", - }, - ast.BitOr: { - "value": "", - "format": "bit32.bor({left}, {right})", - }, - ast.BitAnd: { - "value": "", - "format": "bit32.band({left}, {right})", - }, - ast.BitXor: { - "value": "", - "format": "bit32.bxor({left}, {right})", - }, - } diff --git a/robloxpyc/boolopdesc.py b/robloxpyc/boolopdesc.py deleted file mode 100644 index 665638e..0000000 --- a/robloxpyc/boolopdesc.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Boolean operation description""" -import ast - - -_DEFAULT_FORMAT = "{left} {operation} {right}" - - -class BooleanOperationDesc: - """Binary operation description""" - - OPERATION = { - ast.And: { - "value": "and", - "format": _DEFAULT_FORMAT, - }, - ast.Or: { - "value": "or", - "format": _DEFAULT_FORMAT, - }, - } diff --git a/robloxpyc/climaker.py b/robloxpyc/climaker.py deleted file mode 100644 index f1ba9b9..0000000 --- a/robloxpyc/climaker.py +++ /dev/null @@ -1,233 +0,0 @@ -# TODO - -import sys - -import os - -from platform import uname - -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from loader import loader - from textcompiler import * - from configmanager import * - from util import * - from basecompilers import * -else: - from .loader import loader - from .textcompiler import * - from .configmanager import * - from .util import * - from .basecompilers import * -import threading, shutil - -def newIncli(basefile, func): - def incli(): - # Get all the files inside of the path, look for all of them which are .py and even check inside of folders. If this is happening in the same directory as the script, do it in the sub directory test - path = os.getcwd() - - #global count - #count = 0 - localcount = 0 - for r, d, f in os.walk(path): - for file in f: - if basefile.__class__ == str: - if file.endswith(basefile): - localcount += 1 - else: - for i in basefile: - if file.endswith(i): - localcount += 1 - newloader = loader(localcount) - - for r, d, f in os.walk(path): - for file in f: - if basefile.__class__ == str: - if file.endswith(basefile): - threading.Thread(target=func, args=(r, file, newloader)).start() - #pycompile(r, file) - else: - othercompile(r, file) - else: - found = False - for i in basefile: - if file.endswith(i): - threading.Thread(target=func, args=(r, file, newloader)).start() - #pycompile(r, file) - found = True - if not found: - othercompile(r, file) - - newloader.yielduntil() - - print(colortext.green("Compiled Files!")) - if getconfig("general", "autocompile", False): - action = input("") - if action == "exit": - exit(0) - else: - incli() - else: - exit(0) - - return incli - -def newIncli2(basefile, func): - def incli2(): - # Just like incli, but duplicates the direcotry with -compiled and compiles the files in there, also runs filtercompiledfolder() on the directory - path = os.getcwd()+"-compiled" - if os.path.exists(path): - # delete the folder and child files - shutil.rmtree(path) - shutil.copytree(os.getcwd(), path) - - #global count - #count = 0 - localcount = 0 - for r, d, f in os.walk(path): - for file in f: - # if basefile is a string just check for that, if it is a list, check for all of them - if basefile.__class__ == str: - if file.endswith(basefile): - localcount += 1 - else: - for i in basefile: - if file.endswith(i): - localcount += 1 - - newloader = loader(localcount) - - for r, d, f in os.walk(path): - for file in f: - found = False - for i in basefile: - if file.endswith(i): - threading.Thread(target=func, args=(r, file, newloader)).start() - #pycompile(r, file) - found = True - if not found: - othercompile(r, file) - newloader.yielduntil() - filtercompiledfolder() - print(colortext.green("Compiled Files!")) - if getconfig("general", "autocompile", False): - action = input("") - if action == "exit": - exit(0) - else: - incli2() - return incli2 - -def replaceLuaFiles(r, file, basefile, commentart, luafilecontents): - # create new file with same name but .py and write the lua file contents to it - open(os.path.join(r, file.replace(".lua", basefile)), "x").close() - # write the old file contents as a py comment - open(os.path.join(r, file.replace(".lua", basefile)), "w").write(commentart.format(luafilecontents)) - print(colortext.green("Converted to py "+os.path.join(r, file)+" as "+file.replace(".lua", basefile))) - -def newLanguage(basefile, func, commentart, p=None): - def w(): - try: - incli = newIncli(basefile, func) - incli2 = newIncli2(basefile, func) - - if sys.argv.__len__() >= 1: - if sys.argv[1] == "p": - if p: - p() - else: - print(error("Plugin is not supported for this language.")) - elif sys.argv[1] == "lib": - # sys.argv[2] is the path to the file, create a new file there with the name robloxpyc.lua, and write the library to it - lib() - elif sys.argv[1] == "c": - decreapted("c") - # Go through every lua descendant file in the current directory and delete it and create a new file with the same name but .py - confirm = input(warn("Are you sure? This will delete all .lua files and add a "+basefile+" file with the same name.\n\nType 'yes' to continue.")) - if confirm == "yes": - path = os.getcwd() - - for r, d, f in os.walk(path): - for file in f: - if '.lua' in file: - luafilecontents = "" - with open(os.path.join(r, file), "r") as f: - luafilecontents = f.read() - - os.remove(os.path.join(r, file)) - replaceLuaFiles(r, file, basefile, commentart, luafilecontents) - - elif sys.argv[1] == "cd": - # Duplicate the cwd directory, the original will be renamed to -compiled and the new one will be renamed to the original. For the new one, go through every lua descendant file in the current directory and delete it and create a new file with the same name but .py - confirm = input(warn("Are you sure? This will duplicate the current directory and compile the files in the new directory.\n\nType 'yes' to continue.")) - if confirm == "yes" and uname().system == "Windows": - # check if cwd/default.project.json exists, if it does, then use that as the default project file - #if os.path.exists(os.getcwd()+"/default.project.json"): - # formatdefaultproj(os.getcwd()+"/default.project.json") - # rename directory to -compiled - path_name = os.getcwd() - #os.rename(path_name, path_name+"-compiled") - # duplicate the directory, remove the -compiled from the end - shutil.copytree(path_name, path_name + "-compiled") - # now we have 2 identical directories, one with -compiled and one without. for the one without, go through every lua descendant file in the current directory and delete it and create a new file with the same name but .py - path = os.getcwd() - - for r, d, f in os.walk(backwordreplace(path, "-compiled", "", 1)): - for file in f: - if '.lua' in file: - luafilecontents = "" - with open(os.path.join(r, file), "r") as f: - luafilecontents = f.read() - - os.remove(os.path.join(r, file)) - replaceLuaFiles(r, file, basefile, commentart, luafilecontents) - # create a .rpyc file in the non -compiled directory - open(os.path.join(backwordreplace(path, "-compiled", "", 1), ".rpyc"), "x").close() - # set cwd to not -compiled - os.chdir(backwordreplace(path, "-compiled", "", 1)) - print(info("Completed! You may need to modify the default.package.json or any other equivalent file to make it use the -compiled directory rather than the original.")) - elif confirm == "yes": - # note by CataclysmicDev -> i left this old code here just to make sure its stable on unix but you can delete it and see if the above code works on unix too - path = os.path.join(os.getcwd(), "src") - # check if cwd/default.project.json exists, if it does, then use that as the default project file - #if os.path.exists(os.getcwd()+"/default.project.json"): - # formatdefaultproj(os.getcwd()+"/default.project.json") - # rename directory to -compiled - os.rename(path_name, path_name+"-compiled") - # duplicate the directory, remove the -compiled from the end - shutil.copytree(path_name + "-compiled", path_name) - # now we have 2 identical directories, one with -compiled and one without. for the one without, go through every lua descendant file in the current directory and delete it and create a new file with the same name but .py - path = os.getcwd() - - for r, d, f in os.walk(backwordreplace(path, "-compiled", "", 1)): - for file in f: - if '.lua' in file: - luafilecontents = "" - with open(os.path.join(r, file), "r") as f: - luafilecontents = f.read() - - os.remove(os.path.join(r, file)) - - # create new file with same name but .py and write the lua file contents to it - open(os.path.join(r, file.replace(".lua", basefile)), "x").close() - # write the old file contents as a C++ comment - open(os.path.join(r, file.replace(".lua", basefile)), "w").write("\"\"\"\n"+luafilecontents+"\n\"\"\"") - - print(colortext.green("Converted "+os.path.join(r, file)+" to "+file.replace(".lua", basefile))) - # create a .rpyc file in the non -compiled directory - open(os.path.join(backwordreplace(path, "-compiled", "", 1), ".rpyc"), "x").close() - # set cwd to not -compiled - os.chdir(backwordreplace(path, "-compiled", "", 1)) - print(info("Completed! You may need to modify the default.package.json or any other equivalent file to make it use the -compiled directory rather than the original.")) - elif sys.argv[1] == "w": - print(colortext.magenta("Ready to compile ", os.path.join(os.path.dirname(os.path.realpath(__file__)))+" ...\n Type 'exit' to exit, Press enter to compile.")) - incli() - elif sys.argv[1] == "d": - print(colortext.magenta("Ready to compile ", os.path.join(os.path.dirname(os.path.realpath(__file__)))+" ...\n Type 'exit' to exit, Press enter to compile.")) - incli2() - - except IndexError: - print(error("Invalid amount of arguments!", "roblox-py")) - except KeyboardInterrupt: - print(colortext.red("Aborted!")) - sys.exit(0) - return w diff --git a/robloxpyc/cmpopdesc.py b/robloxpyc/cmpopdesc.py deleted file mode 100644 index 06bdae5..0000000 --- a/robloxpyc/cmpopdesc.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Compare operation description""" -import ast - - -class CompareOperationDesc: - """Compare operation description""" - - OPERATION = { - ast.Eq: "==", - ast.NotEq: "~=", - ast.Lt: "<", - ast.LtE: "<=", - ast.Gt: ">", - ast.GtE: ">=", - ast.In: { - "format": "operator_in({left}, {right})", - }, - ast.NotIn: { - "format": "not operator_in({left}, {right})", - }, - ast.Is: { - "format": "({left} == {right})", - }, - ast.IsNot: { - "format": "not({left} == {right})", - }, - } diff --git a/robloxpyc/cnodevisitor.py b/robloxpyc/cnodevisitor.py deleted file mode 100644 index 4d32baf..0000000 --- a/robloxpyc/cnodevisitor.py +++ /dev/null @@ -1,125 +0,0 @@ -# THIS IS OLD DO NOT USE - - -import clang.cindex -from . import colortext - -# TODO: -## Add depth/indentation to the code -## Add all possible node types - -class NodeVisitor: - def __init__(self): - self.lua_code = "" - - def TRANSLATION_UNIT(self, node, depth=0): - # Visit child nodes of the translation unit - for child in node.get_children(): - self.visit_node(child) - - def FUNCTION_DECL(self, node, depth=0): - # Process function declarations - function_name = node.spelling - self.lua_code += f"function {function_name}()\n" - self.visit_compound_stmt(node.get_children()) - - def VAR_DECL(self, node, depth=0): - # Process variable declarations - variable_name = node.spelling - self.lua_code += f"local {variable_name}\n" - - for child in node.get_children(): - self.visit_node(child) - - def COMPOUND_STMT(self, node, depth=0): - if type(node) == list: - all = node - else: - all = node.get_children() - - for child in all: - self.visit_node(child, depth+1) - - self.lua_code += "end\n" - - for child in node.get_children(): - self.visit_node(child) - - def DECL_STMT(self, node, depth=0): - self.visit_node(node.get_children(), depth+1) - - for child in node.get_children(): - self.visit_node(child) - - def BINARY_OPERATOR(self, node, depth=0): - # Process binary operators - operator = node.spelling - self.lua_code += f"{operator} " - - for child in node.get_children(): - self.visit_node(child) - - def UNARY_OPERATOR(self, node, depth=0): - # Process unary operators - operator = node.spelling - self.lua_code += f"{operator} " - - for child in node.get_children(): - self.visit_node(child) - - def DECL_REF_EXPR(self, node, depth=0): - # Process variable references - variable_name = node.spelling - self.lua_code += f"{variable_name} " - - for child in node.get_children(): - self.visit_node(child) - - def INTEGER_LITERAL(self, node, depth=0): - # Process integer literals - value = node.spelling - self.lua_code += f"{value} " - - for child in node.get_children(): - self.visit_node(child) - - def FLOATING_LITERAL(self, node, depth=0): - # Process floating point literals - value = node.spelling - self.lua_code += f"{value} " - - for child in node.get_children(): - self.visit_node(child) - - def STRING_LITERAL(self, node, depth=0): - # Process string literals - value = node.spelling - self.lua_code += f"{value} " - - for child in node.get_children(): - self.visit_node(child) - - def CHARACTER_LITERAL(self, node, depth=0): - # Process character literals - value = node.spelling - self.lua_code += f"{value} " - - for child in node.get_children(): - self.visit_node(child) - - - - - def visit_node(self, node, depth=0): - # Dispatch visitation based on node kind - if self[node.kind] is not None: - self[node.kind](node, depth+1) - else: - print(colortext.yellow(f"Warning: No visitor method for {node.kind}")) - - # Recursively visit child nodes - for child in node.get_children(): - self.visit_node(child) - - def get_lua_code(self): - return self.lua_code \ No newline at end of file diff --git a/robloxpyc/colortext.py b/robloxpyc/colortext.py deleted file mode 100644 index 1f3b167..0000000 --- a/robloxpyc/colortext.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys - -def red(text, styles = []): - return color(text, 31, styles) -def green(text, styles = []): - return color(text, 32, styles) -def yellow(text, styles = []): - return color(text, 33, styles) -def blue(text, styles = []): - return color(text, 34, styles) -def magenta(text, styles = []): - return color(text, 35, styles) -def cyan(text, styles = []): - return color(text, 36, styles) -def white(text, styles = []): - return color(text, 37, styles) -def rainbow_text(text, end = ""): - colors = ['\033[31m', '\033[33m', '\033[32m', '\033[36m', '\033[34m', '\033[35m'] - i = 0 - for char in text: - print(colors[i % len(colors)] + char, end='') - i += 1 - print('\033[0m', end=end) -def nil(text=""): - return -def color(text, color, styles = []): - style = "" - for s in styles: - if s == "bold": - style += "1;" - elif s == "underline": - style += "4;" - elif s == "reverse": - style += "7;" - elif s == "concealed": - style += "8;" - return "\033["+style+str(color)+"m"+text+"\033[0m" \ No newline at end of file diff --git a/robloxpyc/config.py b/robloxpyc/config.py deleted file mode 100644 index 3ea718c..0000000 --- a/robloxpyc/config.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Python to lua translator config class""" -import sys -import yaml - -class Config: - """Translator config.""" - def __init__(self, filename=None): - self.data = { - "class": { - "return_at_the_end": False, - }, - } - - if filename is not None: - self.load(filename) - - def load(self, filename): - """Load config from the file""" - try: - with open(filename, "r") as stream: - data = yaml.load(stream) - self.data.update(data) - except FileNotFoundError: - pass # Use a default config if the file not found - except yaml.YAMLError as ex: - print(ex) - - def __getitem__(self, key): - """Get data values""" - return self.data[key] diff --git a/robloxpyc/configmanager.py b/robloxpyc/configmanager.py deleted file mode 100644 index d665b8f..0000000 --- a/robloxpyc/configmanager.py +++ /dev/null @@ -1,51 +0,0 @@ -# CONFIG -# CFG will be in the same directory as this file -import pickle, os -cfgPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "__communication__/cfg.pkl") -def getconfig(arg1, arg2, default="None"): - try: - # Load the config file if it exists, or create a new one if it doesn't - if os.path.exists(cfgPath): - with open(cfgPath, "rb") as f: - cfg = pickle.load(f) - else: - cfg = {} - - # Get the value from the config file, or use the default value if it doesn't exist - value = cfg.get(arg1, {}).get(arg2, default) - - # Update the config file with the default value if it doesn't exist - if arg1 not in cfg: - cfg[arg1] = {} - if arg2 not in cfg[arg1]: - cfg[arg1][arg2] = default - with open(cfgPath, "wb") as f: - pickle.dump(cfg, f) - - return value - except EOFError: - # The file is empty, write a {} to it - with open(cfgPath, "wb") as f: - pickle.dump({}, f) - return getconfig(arg1, arg2, default) - -def setconfig(arg1, arg2, value, ignore=None): - try: - # Load the config file if it exists, or create a new one if it doesn't - if os.path.exists(cfgPath): - with open(cfgPath, "rb") as f: - cfg = pickle.load(f) - else: - cfg = {} - - # Set the value in the config file and save it - if arg1 not in cfg: - cfg[arg1] = {} - cfg[arg1][arg2] = value - with open(cfgPath, "wb") as f: - pickle.dump(cfg, f) - except EOFError: - # The file is empty, write a {} to it - with open(cfgPath, "wb") as f: - pickle.dump({}, f) - return setconfig(arg1, arg2, value, ignore=ignore) diff --git a/robloxpyc/context.py b/robloxpyc/context.py deleted file mode 100644 index 49b1efb..0000000 --- a/robloxpyc/context.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Class to store the python code context""" -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from symbolsstack import SymbolsStack - from tokenendmode import TokenEndMode -else: - from .symbolsstack import SymbolsStack - from .tokenendmode import TokenEndMode - - -class Context: - """Class to store the python code context""" - def __init__(self, values=None): - values = values if values is not None else { - "token_end_mode": TokenEndMode.LINE_FEED, - "class_name": "", - "locals": SymbolsStack(), - "globals": SymbolsStack(), # Not working yet - "loop_label_name": "", - "docstring": False, - } - - self.ctx_stack = [values] - - def last(self): - """Return actual context state""" - return self.ctx_stack[-1] - - def push(self, values): - """Push new context state with new values""" - value = self.ctx_stack[-1].copy() - value.update(values) - self.ctx_stack.append(value) - - def pop(self): - """Pop last context state""" - assert len(self.ctx_stack) > 1, "Pop context failed. This is a last context in the stack." - return self.ctx_stack.pop() diff --git a/robloxpyc/cpAST.py b/robloxpyc/cpAST.py deleted file mode 100644 index 08696b3..0000000 --- a/robloxpyc/cpAST.py +++ /dev/null @@ -1,18 +0,0 @@ -# THIS IS OLD DO NOT USE - -""" -Dedicated to parsing C/C++ code into ASTs using libclang. -Pass the code on to the C(++) translator. -""" - -import clang.cindex as clang - -def get_ast(file_path): - index = clang.Index.create() - translation_unit = index.parse(file_path) - return translation_unit.cursor - -def print_ast(node, depth=0): - print(' ' * depth + str(node.kind) + ' : ' + node.spelling) - for child in node.get_children(): - print_ast(child, depth + 1) diff --git a/robloxpyc/ctranslator.py b/robloxpyc/ctranslator.py deleted file mode 100644 index b13f638..0000000 --- a/robloxpyc/ctranslator.py +++ /dev/null @@ -1,18 +0,0 @@ -# THIS IS OLD DO NOT USE - -from .cpAST import get_ast, print_ast -from .cnodevisitor import NodeVisitor - -def readast(node, depth, calc): - calc(node, depth) - for child in node.get_children(): - print_ast(child, depth + 1, calc) - -def translate(file_path): - ast = get_ast(file_path) - print_ast(ast) - - newNodeVisitor = NodeVisitor() - newNodeVisitor.visit_node(ast) - - print(newNodeVisitor.get_lua_code()) \ No newline at end of file diff --git a/robloxpyc/errormanager.py b/robloxpyc/errormanager.py deleted file mode 100644 index 4d5bd4a..0000000 --- a/robloxpyc/errormanager.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Error system for robloxpyc""" -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - import colortext, configmanager -else: - from . import colortext, configmanager -import subprocess, traceback - -def candcpperror(): - print(warn("C and C++ are not supported in this build, coming soon! \n\n contributions on github will be greatly appreciated!")) -def error(errormessage, source=""): - if source != "": - source = colortext.white(" ("+source+") ") - if configmanager.getconfig("general", "goofy", False): - subprocess.call(["say", errormessage]) - return(colortext.red("error ", ["bold"])+source+errormessage) -def warn(warnmessage, source=""): - if source != "": - source = colortext.white(" ("+source+") ") - return(colortext.yellow("warning ", ["bold"])+source+warnmessage) -def info(infomessage, source=""): - if source != "": - source = colortext.white(" ("+source+") ") - return(colortext.blue("info ", ["bold"])+source+infomessage) -def debug(infomessage): - if configmanager.getconfig("general", "traceback", False): - print(colortext.blue("debug ", ["bold"])+infomessage) - print(traceback.format_exc()) -def decreapted(source=""): - if source != "": - source = colortext.white(" ("+source+") ") - print(colortext.yellow("decreapted ", ["bold"])+source+"This feature is decreapted and will be removed in a future version of roblox-pyc") \ No newline at end of file diff --git a/robloxpyc/header.py b/robloxpyc/header.py deleted file mode 100644 index 442e0ed..0000000 --- a/robloxpyc/header.py +++ /dev/null @@ -1,49 +0,0 @@ -headertemplate = """--/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -{} ------------------------------------------------------------------------------ -""" -lunarheadertemplate = """--/ Compiled using roblox-pyc | Lunar compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local import, builtin = _G.pyc(script).lunar - -{} ------------------------------------------------------------------------------ -""" - -pyfooter = """ - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - -""" - -def header(functions): - code = "" - for i in functions: - code += "local "+i+" = builtin."+i+"\n" - - #print(code) - return headertemplate.format(code) - -def lunarheader(functions): - code = "" - for i in functions: - code += "local "+i+" = builtin."+i+"\n" - - #print(code) - return lunarheadertemplate.format(code) \ No newline at end of file diff --git a/robloxpyc/installationmanager.py b/robloxpyc/installationmanager.py deleted file mode 100644 index a82fc3d..0000000 --- a/robloxpyc/installationmanager.py +++ /dev/null @@ -1,86 +0,0 @@ -"""Manages updating and installing dependencies""" - -# PYPI -from packaging import version - -# FILES -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from errormanager import * -else: - from .errormanager import * - -# BUILTIN -import subprocess,requests,pkg_resources, os - -def check_luarocks(): - try: - subprocess.call(["luarocks", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) - return True - except FileNotFoundError: - return False - -def check_moonscript(): - try: - subprocess.call(["moonc", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) - return True - except FileNotFoundError: - return False - -def install_luarocks(): - print("Installing LuaRocks...") - subprocess.call(["apt-get", "install", "-y", "luarocks"]) - -def install_moonscript(): - print("Installing MoonScript...") - subprocess.call(["luarocks", "install", "moonscript", "--dev"]) - -def checkboth(): - if check_luarocks() == False: - print(warn("LuaRocks is not installed, installing...")) - install_luarocks() - if check_moonscript() == False: - print(warn("MoonScript is not installed, installing...")) - install_moonscript() - -def get_latest_version(): - url = f"https://pypi.org/pypi/roblox-pyc/json" - response = requests.get(url) - data = response.json() - return data["info"]["version"] - -def check_for_updates(): - current_version = pkg_resources.get_distribution("roblox-pyc").version - latest_version = get_latest_version() - if version.parse(latest_version) > version.parse(current_version): - print(info(f"Update available to {latest_version}, you are currently using {current_version}")) - choice = input("\t\tDo you want to update? (yes/no): ").lower() - if choice == "yes": - # Add the pip upgrade command here. - # Get cfg.pkl - script_dir = os.path.dirname(os.path.realpath(__file__)) - returnval = "" - try: - with open(os.path.join(script_dir, "__communication__/cfg.pkl"), "rb") as file: - returnval = file.read() - except: - print(error("Failed to safe-update, data is corrupted. Would you like to force-update, you may lose configuration data.", "auto-updater")) - choice = input("\t\tDo you want to force-update? (yes/no): ").lower() - if not choice == "yes": - sys.exit() - subprocess.run(["pip", "install", f"roblox-pyc=={latest_version}"]) - with open(os.path.join(script_dir, "__communication__/cfg.pkl"), "wb") as file: - file.write(returnval) - - -def check_npm(): - try: - subprocess.call(["npm", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) - return True - except FileNotFoundError: - return False -def install_npm(): - print("Installing NPM...") - subprocess.call(["apt-get", "install", "-y", "npm"]) - diff --git a/robloxpyc/loader.py b/robloxpyc/loader.py deleted file mode 100644 index da469bd..0000000 --- a/robloxpyc/loader.py +++ /dev/null @@ -1,32 +0,0 @@ -# LOADING -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - import colortext -else: - from . import colortext - -from time import sleep -from tqdm import tqdm - -class loader: - self = {} - def __init__(self, max): - print("\n\n") - self.max = max - self.current = 0 - self.tqdm = tqdm(total=max) - - def yielduntil(self): - global count - while self.max != self.current: - sleep(.5) - self.tqdm.update(self.max-self.current ) - self.tqdm.close() - def update(self, amount): - self.tqdm.update(amount) - def error(self): - self.tqdm.write(colortext.red("paused!", ["bold"])) - self.current = self.max - self.tqdm.close() - \ No newline at end of file diff --git a/robloxpyc/loopcounter.py b/robloxpyc/loopcounter.py deleted file mode 100644 index 9849d2d..0000000 --- a/robloxpyc/loopcounter.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Label counter for the loops continue""" - -class LoopCounter: - """Loop counter""" - COUNTER = 0 - - @staticmethod - def get_next(): - """Return next loop continue label name""" - LoopCounter.COUNTER += 1 - return "continue {}".format(LoopCounter.COUNTER) diff --git a/robloxpyc/luainit.py b/robloxpyc/luainit.py deleted file mode 100644 index ff15a59..0000000 --- a/robloxpyc/luainit.py +++ /dev/null @@ -1,160 +0,0 @@ -import os -import pip -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - import colortext as colortext -else: - from . import colortext as colortext - -initcode = "" - -try: - # check for a luainitlua.lua file from the same directory as this file - with open(os.path.join(os.path.dirname(__file__), "luainitlua.lua")) as f: - initcode = f.read() -except FileNotFoundError: - print(colortext.yellow("warning", ["bold"])+" Due to a bug, lib will not work, please report this issue to the github repo, discord server, or the devforum post\nthanks!") -allfunctions = "safeadd, list, dict, python, staticmethod, classsmethod, class, range, __name__, len, abs, str, int, sum, max, min, reversed, split, round, all, any, ord, char, callable, zip, float, format, hex, id, map, bool, divmod, slice, operator_in, asynchronousfunction, match, anext, ascii, dir, getattr, globals, hasattr, input, isinstance, issubclass, iter, locals, oct, open, ord, pow, eval, exec, filter, frozenset, aiter, bin, complex, delattr, enumerate, breakpoint, bytearray, bytes, compile, help, memoryview, repr, sorted, vars, __import_, formatmod" -lunarfunctions = "" -robloxfunctions = """["assert"] = "function", - ["error"] = "function", - ["getfenv"] = "function", - ["getmetatable"] = "function", - ["ipairs"] = "function", - ["loadstring"] = "function", - ["newproxy"] = "function", - ["next"] = "function", - ["pairs"] = "function", - ["pcall"] = "function", - ["print"] = "function", - ["rawequal"] = "function", - ["rawget"] = "function", - ["rawlen"] = "function", - ["rawset"] = "function", - ["select"] = "function", - ["setfenv"] = "function", - ["setmetatable"] = "function", - ["tonumber"] = "function", - ["tostring"] = "function", - ["unpack"] = "function", - ["xpcall"] = "function", - ["collectgarbage"] = "function", - ["_G"] = "table", - ["_VERSION"] = "string", - ["bit32"] = "table", - ["coroutine"] = "table", - ["debug"] = "table", - ["math"] = "table", - ["os"] = "table", - ["string"] = "table", - ["table"] = "table", - ["utf8"] = "table", - ["DebuggerManager"] = "function", - ["delay"] = "function", - ["gcinfo"] = "function", - ["PluginManager"] = "function", - ["require"] = "function", - ["settings"] = "function", - ["spawn"] = "function", - ["tick"] = "function", - ["time"] = "function", - ["UserSettings"] = "function", - ["wait"] = "function", - ["warn"] = "function", - ["Delay"] = "function", - ["ElapsedTime"] = "function", - ["elapsedTime"] = "function", - ["printidentity"] = "function", - ["Spawn"] = "function", - ["Stats"] = "function", - ["stats"] = "function", - ["Version"] = "function", - ["version"] = "function", - ["Wait"] = "function", - ["ypcall"] = "function", - ["game"] = "Instance", - ["plugin"] = "Instance", - ["script"] = "Instance", - ["shared"] = "Instance", - ["workspace"] = "Instance", - ["Game"] = "Instance", - ["Workspace"] = "Instance", - ["Axes"] = "table", - ["BrickColor"] = "table", - ["CatalogSearchParams"] = "table", - ["CFrame"] = "table", - ["Color3"] = "table", - ["ColorSequence"] = "table", - ["ColorSequenceKeypoint"] = "table", - ["DateTime"] = "table", - ["DockWidgetPluginGuiInfo"] = "table", - ["Enum"] = "table", - ["Faces"] = "table", - ["FloatCurveKey"] = "table", - ["Font"] = "table", - ["Instance"] = "table", - ["NumberRange"] = "table", - ["NumberSequence"] = "table", - ["NumberSequenceKeypoint"] = "table", - ["OverlapParams"] = "table", - ["PathWaypoint"] = "table", - ["PhysicalProperties"] = "table", - ["Random"] = "table", - ["Ray"] = "table", - ["RaycastParams"] = "table", - ["Rect"] = "table", - ["Region3"] = "table", - ["Region3int16"] = "table", - ["RotationCurveKey"] = "table", - ["SharedTable"] = "table", - ["task"] = "table", - ["TweenInfo"] = "table", - ["UDim"] = "table", - ["UDim2"] = "table", - ["Vector2"] = "table", - ["Vector2int16"] = "table", - ["Vector3"] = "table", - ["Vector3int16"] = "table", -""" -allfunctions = allfunctions.split(", ") -lunarfunctions = lunarfunctions.split(", ") - -# Parse robloxfunctions to something that looks like allfunctions -robloxfunctions = robloxfunctions.replace("\n", "").replace("\t", "").replace(" ", "").replace('"', "").replace("'", "").replace("{", "").replace("}", "").replace("[", "").replace("]", "").split(",") -for i in range(len(robloxfunctions)): - item = robloxfunctions[i] - if item == "": - # Remove from list - robloxfunctions.pop(i) - else: - # Split by = and the first item is the name - robloxfunctions[i] = item.split("=")[0] - -def generatewithlibraries (libs): - # Every item in libs is a table with 3 values - # name (what to download by) - # data (source code) - # var (what variable is the source code stored in) - - # The initcode has 2 comments, --{SOURCECODEHERE}-- and --{ITEMSHERE}--. Replace SOURCECODEHERE with all of the source codes seprated by newlines - # and for ITEMSHERE, "" = - - currentcode = initcode - sources = [] - items = {} - - for i in range(len(libs)): - sources.append(libs[i]["data"]) - items[libs[i]["name"]] = libs[i]["var"] - - sourcestext = "\n".join(sources) - itemstext = "" - - for i in range(len(items)): - itemstext += f'["{list(items.keys())[i]}"] = {list(items.values())[i]}\n' - - currentcode = currentcode.replace("--{SOURCECODEGOESHERE}--", sourcestext) - currentcode = currentcode.replace("--{ITEMSGOHERE}--", itemstext) - - return currentcode diff --git a/robloxpyc/luainitlua.lua b/robloxpyc/luainitlua.lua deleted file mode 100644 index 1e0e79c..0000000 --- a/robloxpyc/luainitlua.lua +++ /dev/null @@ -1,1240 +0,0 @@ ---// AsynchronousAI @Dev98799 \\-- ----------------------------------------------------------------------------------------- --- stdlib used to hold built in functions wrappers and libraries -- ----------------------------------------------------------------------------------------- - --- stdlib Version 2.5.9 -- - -local module = { } - --- Language used for gamewrapper (from Highlighter by boatbomber) -local language = { - -- Luau Functions - ["assert"] = "function", - ["error"] = "function", - ["getfenv"] = "function", - ["getmetatable"] = "function", - ["ipairs"] = "function", - ["loadstring"] = "function", - ["newproxy"] = "function", - ["next"] = "function", - ["pairs"] = "function", - ["pcall"] = "function", - ["print"] = "function", - ["rawequal"] = "function", - ["rawget"] = "function", - ["rawlen"] = "function", - ["rawset"] = "function", - ["select"] = "function", - ["setfenv"] = "function", - ["setmetatable"] = "function", - ["tonumber"] = "function", - ["tostring"] = "function", - ["unpack"] = "function", - ["xpcall"] = "function", - - -- Luau Functions (Deprecated) - ["collectgarbage"] = "function", - - -- Luau Variables - ["_G"] = "table", - ["_VERSION"] = "string", - - -- Luau Tables - ["bit32"] = "table", - ["coroutine"] = "table", - ["debug"] = "table", - ["math"] = "table", - ["os"] = "table", - ["string"] = "table", - ["table"] = "table", - ["utf8"] = "table", - - -- Roblox Functions - ["DebuggerManager"] = "function", - ["delay"] = "function", - ["gcinfo"] = "function", - ["PluginManager"] = "function", - ["require"] = "function", - ["settings"] = "function", - ["spawn"] = "function", - ["tick"] = "function", - ["time"] = "function", - ["UserSettings"] = "function", - ["wait"] = "function", - ["warn"] = "function", - - -- Roblox Functions (Deprecated) - ["Delay"] = "function", - ["ElapsedTime"] = "function", - ["elapsedTime"] = "function", - ["printidentity"] = "function", - ["Spawn"] = "function", - ["Stats"] = "function", - ["stats"] = "function", - ["Version"] = "function", - ["version"] = "function", - ["Wait"] = "function", - ["ypcall"] = "function", - - -- Roblox Variables - ["game"] = "Instance", - ["plugin"] = "Instance", - ["script"] = "Instance", - ["shared"] = "Instance", - ["workspace"] = "Instance", - - -- Roblox Variables (Deprecated) - ["Game"] = "Instance", - ["Workspace"] = "Instance", - - -- Roblox Tables - ["Axes"] = "table", - ["BrickColor"] = "table", - ["CatalogSearchParams"] = "table", - ["CFrame"] = "table", - ["Color3"] = "table", - ["ColorSequence"] = "table", - ["ColorSequenceKeypoint"] = "table", - ["DateTime"] = "table", - ["DockWidgetPluginGuiInfo"] = "table", - ["Enum"] = "table", - ["Faces"] = "table", - ["FloatCurveKey"] = "table", - ["Font"] = "table", - ["Instance"] = "table", - ["NumberRange"] = "table", - ["NumberSequence"] = "table", - ["NumberSequenceKeypoint"] = "table", - ["OverlapParams"] = "table", - ["PathWaypoint"] = "table", - ["PhysicalProperties"] = "table", - ["Random"] = "table", - ["Ray"] = "table", - ["RaycastParams"] = "table", - ["Rect"] = "table", - ["Region3"] = "table", - ["Region3int16"] = "table", - ["RotationCurveKey"] = "table", - ["SharedTable"] = "table", - ["task"] = "table", - ["TweenInfo"] = "table", - ["UDim"] = "table", - ["UDim2"] = "table", - ["Vector2"] = "table", - ["Vector2int16"] = "table", - ["Vector3"] = "table", - ["Vector3int16"] = "table", -} -function backwordreplace(s, old, new, occurrence) -- Lua implementation of the python function in robloxpy.py line ~600 - local li = {} - local i = 1 - while true do - local j = string.find(s, old, i, true) - if not j then - break - end - table.insert(li, string.sub(s, i, j - 1)) - i = j + #old - if #li == occurrence then - break - end - end - table.insert(li, string.sub(s, i)) - return table.concat(li, new) -end -local function parse_path(path, start_obj) - local obj = start_obj or game - local parts = string.split(path, "/") - for i, part in ipairs(parts) do - if part == "" then - obj = game - elseif part == "~" then - obj = game - elseif part == ".." then - obj = obj.Parent - else - if not obj:FindFirstChild(part) then - error("Object not found: " .. part .." in "..obj.Name.."\n\n\tDo not add .json, .txt, etc. to the end of file names, this version doesnt support them.") - return nil - end - obj = obj:FindFirstChild(part) - end - end - return obj -end - -local slicefun = function (seq, start, stop, step) - local sliced = {} - local len = #seq - start = start or 1 - stop = stop or len - step = step or 1 - if start < 0 then - start = len + start + 1 - end - if stop < 0 then - stop = len + stop + 1 - end - for i = start, stop - 1, step do - table.insert(sliced, seq[i]) - end - return sliced -end -function endswith(s, suffix) -- like string.endswith in python - return string.sub(s, -string.len(suffix)) == suffix -end -local wrappercache = setmetatable({}, {__mode = "k"}) -local wrap, unwrap -unwrap = function(wrapped) - if type(wrapped) == "table" then - local real = {} - for k,v in next,wrapped do - real[k] = unwrap(v) - end - return real - else - local real = wrappercache[wrapped] - if real == nil then - return wrapped - end - return real - end -end -wrap = function(real, functions) - functions = functions or {} - for w,r in next,wrappercache do - if r == real then - return w - end - end - - if type(real) == "userdata" then - local fake = newproxy(true) - local meta = getmetatable(fake) - - meta.__index = function(s,k) - - if table.find(functions, k) then - return functions[k] - end - if real[k] then - if typeof(real[k]) == "RBXScriptSignal" then - local newSignal = {} - setmetatable(newSignal, { - __call = function(func) - real:Connect(func) - end, - __index = function(index) return real[index] end - }) - return newSignal - elseif type(real[k]) == "function" then - return function(...) - local returnval - local items = unpack(table.pack(...)) - local s, e = pcall(function() - returnval = wrap(real[k](items)) - end) - if (not s) then - local rawcall = real[k](real, items) - returnval = wrap(rawcall) - elseif not s then - error(e) - end - return returnval - end - end - return wrap(real[k], functions) - end - end - - meta.__newindex = function(s,k,v) - real[k] = v - end - - meta.__tostring = function(s) - return tostring(real) - end - - wrappercache[fake] = real - return fake - - elseif type(real) == "function" then - return function(special, ...) - if special == selfcval then - return wrap(real(real, ...)) - end - return wrap(real(special, ...)) - end - - elseif type(real) == "table" then - local fake = {} - for k,v in next,real do - fake[k] = wrap(v) - end - return fake - - else - return real - end -end - -local function set_metatable(var, mt) - local var_type = typeof(var) - if var_type == "Instance" then - var:SetAttribute("__metatable", mt) - elseif var_type == "table" then - setmetatable(var, mt) - end - return var -end -local function set_fun_meta(f, rmt) - return function() - local returnval = f() - if returnval == nil then return end - if type(returnval) == "function" then - return set_fun_meta(returnval, rmt) - else - set_metatable(rmt) - end - end -end -local gtype -if not typeof then - gtype = function(obj) - local type = type(obj) - if type == "table" then - if obj._is_list then - return "list" - end - if obj._is_dict then - return "dict" - end - end - return type - end -else - gtype = typeof -end -local typeof = gtype - - - -function list(t) - local result = {} - - result._is_list = true - - result._data = {} - for _, v in ipairs(t) do - table.insert(result._data, v) - end - - local methods = {} - - methods.append = function(value) - table.insert(result._data, value) - end - - methods.extend = function(iterable) - for value in iterable do - table.insert(result._data, value) - end - end - - methods.insert = function(index, value) - table.insert(result._data, index, value) - end - - methods.remove = function(value) - for i, v in ipairs(result._data) do - if value == v then - table.remove(result._data, i) - break - end - end - end - - methods.pop = function(index) - index = index or #result._data - local value = result._data[index] - table.remove(result._data, index) - return value - end - - methods.clear = function() - result._data = {} - end - - methods.index = function(value, start, end_) - start = start or 1 - end_ = end_ or #result._data - - for i = start, end_, 1 do - if result._data[i] == value then - return i - end - end - - return nil - end - - methods.count = function(value) - local cnt = 0 - for _, v in ipairs(result._data) do - if v == value then - cnt = cnt + 1 - end - end - - return cnt - end - - methods.sort = function(key, reverse) - key = key or nil - reverse = reverse or false - - table.sort(result._data, function(a, b) - if reverse then - return a < b - end - - return a > b - end) - end - - methods.reverse = function() - local new_data = {} - for i = #result._data, 1, -1 do - table.insert(new_data, result._data[i]) - end - - result._data = new_data - end - - methods.copy = function() - return list(result._data) - end - - local iterator_index = nil - - setmetatable(result, { - __index = function(self, index) - if typeof(index) == "number" then - if index < 0 then - index = #result._data + index - end - return rawget(result._data, index + 1) - end - return methods[index] - end, - __newindex = function(self, index, value) - result._data[index] = value - end, - __call = function(self, _, idx) - if idx == nil and iterator_index ~= nil then - iterator_index = nil - end - - local v = nil - iterator_index, v = next(result._data, iterator_index) - - return v - end, - }) - - return result -end -function dict(t) - local result = {} - - result._is_dict = true - - result._data = {} - for k, v in pairs(t) do - result._data[k] = v - end - - local methods = {} - - local key_index = nil - - methods.clear = function() - result._data = {} - end - - methods.copy = function() - return dict(result._data) - end - - methods.get = function(key, default) - default = default or nil - if result._data[key] == nil then - return default - end - - return result._data[key] - end - - methods.items = function() - return pairs(result._data) - end - - methods.keys = function() - return function(self, idx, _) - if idx == nil and key_index ~= nil then - key_index = nil - end - - key_index, _ = next(result._data, key_index) - return key_index - end - end - - methods.pop = function(key, default) - default = default or nil - if result._data[key] ~= nil then - local value = result._data[key] - result._data[key] = nil - return key, value - end - - return key, default - end - - methods.popitem = function() - local key, value = next(result._data) - if key ~= nil then - result._data[key] = nil - end - - return key, value - end - - methods.setdefault = function(key, default) - if result._data[key] == nil then - result._data[key] = default - end - - return result._data[key] - end - - methods.update = function(t) - assert(t._is_dict) - - for k, v in t.items() do - result._data[k] = v - end - end - - methods.values = function() - return function(self, idx, _) - if idx == nil and key_index ~= nil then - key_index = nil - end - - key_index, value = next(result._data, key_index) - return value - end - end - - setmetatable(result, { - __index = function(self, index) - if typeof(index) == "string" then - -- If it starts with SLICE! then it is a slice, get the start, stop, and step values. Sometimes the 3rd value is not there, so we need to check for that - if string.sub(index, 1, 6) == "SLICE!" then - local start, stop, step = string.match(index, "SLICE!%((%d+), (%d+), (%d+)%)") - if (not stop) and (not step) and start then -- 1 value - start = string.match(index, "SLICE!%((%d+), (%d+)%)") - step = 1 - stop = -1 - elseif not step then -- 2 values - start, stop = string.match(index, "SLICE!%((%d+), (%d+)%)") - step = 1 - end - return slicefun(self, tonumber(start), tonumber(stop), tonumber(step)) - end - end - if result._data[index] ~= nil then - return result._data[index] - end - return methods[index] - end, - __newindex = function(self, index, value) - result._data[index] = value - end, - __call = function(self, _, idx) - if idx == nil and key_index ~= nil then - key_index = nil - end - - key_index, _ = next(result._data, key_index) - - return key_index - end, - }) - - return result -end ---{SOURCECODEGOESHERE}-- - -local libraries = { - ["example"] = function() print("Example library!") end, - --{ITEMSGOHERE}-- -} -local dependenciesfolder = script.Parent -local pythonBuiltIn = function(inScript) -- python built in - local items = { - list = list, dict = dict, -- class meta - staticmethod = function(old_fun) -- staticmethod - local wrapper = function(first, ...) - return old_fun(...) - end - - return wrapper - end, - classmethod = function(old_fun) -- classmethod - local wrapper = function(first, ...) - return old_fun(first, ...) - end - - return wrapper - end, - class = function(class_init, bases) -- class - bases = bases or {} - - local c = {} - - for _, base in ipairs(bases) do - for k, v in pairs(base) do - c[k] = v - end - end - - c._bases = bases - - c = class_init(c) - - local mt = getmetatable(c) or {} - mt.__call = function(_, ...) - local object = {} - - setmetatable(object, { - __index = function(tbl, idx) - local method = c[idx] - if typeof(method) == "function" then - return function(...) - return c[idx](object, ...) - end - end - - return method - end, - }) - - if typeof(object.__init__) == "function" then - object.__init__(...) - end - - return object - end - - setmetatable(c, mt) - - return c - end, - range = function(s, e) -- range() - local tb = {} - local a = 0 - local b = 0 - if not e then a=1 else a=s end - if not e then b=s else b=e end - for i = a, b do - tb[#tb+1] = i - end - return tb - end, - __name__ = if inScript:IsA("BaseScript") then "__main__" else inScript.Name , - len = function(x) return #x end, -- len() - abs = math.abs, -- abs() - str = tostring, -- str() - int = tonumber, -- int() - - sum = function(tbl) --sum() - local total = 0 - for _, v in ipairs(tbl) do - total = total + v - end - return total - end, - - -- Maximum value in a table - max = function(tbl) --max() - local maxValue = -math.huge - for _, v in ipairs(tbl) do - if v > maxValue then - maxValue = v - end - end - return maxValue - end, - - -- Minimum value in a table - min = function(tbl) --min() - local minValue = math.huge - for _, v in ipairs(tbl) do - if v < minValue then - minValue = v - end - end - return minValue - end, - - -- Reversed version of a table or string - reversed = function(seq) -- reversed() - local reversedSeq = {} - local length = #seq - for i = length, 1, -1 do - reversedSeq[length - i + 1] = seq[i] - end - return reversedSeq - end, - - -- Splitting a string into a table of substrings - split = function(str, sep) -- split - local substrings = {} - local pattern = string.format("([^%s]+)",sep or "%s") - for substring in string.gmatch(str, pattern) do - table.insert(substrings, substring) - end - return substrings - end, - - round = math.round, -- round() - - all = function (iter) -- all() - for i, v in iter do if not v then return false end end - - return true - end, - - any = function (iter) -- any() - for i, v in iter do - if v then return true end - end - return false - end, - - ord = string.byte, -- ord - chr = string.char, -- chr - - callable = function(fun) -- callable() - if rawget(fun) ~= fun then warn("At the momement Roblox.py's function callable() does not fully support metatables.") end - return typeof(rawget(fun)) == "function" - end, - float = tonumber, -- float() - super = function() - error("roblox-pyc does not has a Lua implementation of the function `super`. Use `self` instead") - end, - format = function(format, ...) -- format - local args = {...} - local num_args = select("#", ...) - - local formatted_string = string.gsub(format, "{(%d+)}", function(index) - index = tonumber(index) - if index >= 1 and index <= num_args then - return tostring(args[index]) - else - return "{" .. index .. "}" - end - end) - - return formatted_string - end, - - hex = function (value) -- hex - return string.format("%x", value) - end, - - id = function (obj) -- id - return print(tostring({obj}):gsub("table: ", ""):split(" ")[1]) - end, - map = function (func, ...) --map - local args = {...} - local result = {} - local num_args = select("#", ...) - - local shortest_length = math.huge - for i = 1, num_args do - local arg = args[i] - local arg_length = #arg - if arg_length < shortest_length then - shortest_length = arg_length - end - end - - for i = 1, shortest_length do - local mapped_args = {} - for j = 1, num_args do - local arg = args[j] - table.insert(mapped_args, arg[i]) - end - table.insert(result, func(unpack(mapped_args))) - end - - return result - end, - bool = function(x) -- bool - if x == false or x == nil or x == 0 then - return false - end - - if typeof(x) == "table" then - if x._is_list or x._is_dict then - return next(x._data) ~= nil - end - end - - return true - end, - divmod = function(a, b) -- divmod - local res = { math.floor(a / b), math.fmod(a, b) } - return unpack(res) - end, - slice = slicefun, - operator_in = function (item, items) -- operator_in() - if type(items) == "table" then - for v in items do - if v == item then - return true - end - end - elseif type(items) == "string" and type(item) == "string" then - return string.find(items, item, 1, true) ~= nil - end - - return false - end, - asynchronousfunction = function(func) -- asynchronousfunction - return function(...) - local all = {...} - coroutine.wrap(function() - func(unpack(all)) - end)() - end - end, - match = function(value, values) -- match - if values[value] then - return values[value]() - elseif values["default"] then - return values["default"]() - end - end, - - anext = function (iterator) -- anext - local status, value = pcall(iterator) - if status then - return value - end - end, - - ascii = function (obj) -- ascii - return string.format("%q", tostring(obj)) - end, - dir = function (obj) -- dir - local result = {} - for key, _ in pairs(obj) do - table.insert(result, key) - end - return result - end, - getattr = function (obj, name, default) -- getattr - local value = obj[name] - if value == nil then - return default - end - return value - end, - globals = function () -- globals - return _G - end, - hasattr = function (obj, name) --hasattr - return obj[name] ~= nil - end, - input = function (prompt) -- input - if not io then error("io is not enabled") end - io.write(prompt) - return io.read() - end, - isinstance = function (obj, class) -- isinstance - return type(obj) == class - end, - issubclass = function (cls, classinfo) -- issubclass - local mt = getmetatable(cls) - while mt do - if mt.__index == classinfo then - return true - end - mt = getmetatable(mt.__index) - end - return false - end, - iter = function (obj) -- iter - if type(obj) == "table" and obj.__iter__ ~= nil then - return obj.__iter__ - end - return nil - end, - locals = function () -- locals - return _G - end, - -- oct() - oct = function (num) --oct - return string.format("%o", num) - end, - - -- open() - open = function (path, mode) - local obj = parse_path(path, inScript) - if obj:IsA("ModuleScript") then - local source = fromFileImport(obj) - if mode == "r" then - return source.Contents or error("File is not in correct roblox-pyc format, cannot be read.") - elseif mode == "w" then - return { - write = function(self, data) - obj:SetSource(data) - end, - close = function(self) - --obj:SaveSource() - return -- do nothing - end - } - else - error("Invalid mode, at the moment only r and w are supported: " .. mode) - end - else - error("Object is not a LuaSourceContainer: " .. path) - end - end, - - - -- pow() - pow = function (base, exponent, modulo) --pow - if modulo ~= nil then - return math.pow(base, exponent) % modulo - else - return base ^ exponent - end - end, - - -- eval() - eval = function (expr, env) - return loadstring(expr)() - end, - - -- exec() - exec = loadstring, - - -- filter() - filter = function (predicate, iterable) - local result = {} - for _, value in ipairs(iterable) do - if predicate(value) then - table.insert(result, value) - end - end - return result - end, - - -- frozenset() - frozenset = function (...) - local elements = {...} - local frozenSet = {} - for _, element in ipairs(elements) do - frozenSet[element] = true - end - return frozenSet - end, - -- aiter() - aiter = function (iterable) -- aiter - return pairs(iterable) - end, - - -- bin() - bin = function(num: number) - local bits = {} - repeat - table.insert(bits, 1, num % 2) - num = math.floor(num / 2) - until num == 0 - return "0b" .. table.concat(bits) - end, - -- complex() - complex = function (real, imag) -- complex - return { real = real, imag = imag } - end, - - -- delattr() - deltaattr = function (object, attribute) -- delattr - object[attribute] = nil - end, - - -- enumerate() - enumerate = function (iterable) -- enumerate - local i = 0 - return function() - i = i + 1 - local value = iterable[i] - if value ~= nil then - return i, value - end - end - end, - - -- breakpoint() - breakpoint = function () -- breakpoint - debug.traceback("Breakpoint hit!") - - end, - - -- bytearray() - bytearray = function (arg) -- bytearray - if type(arg) == "string" then - local bytes = {} - for i = 1, #arg do - table.insert(bytes, string.byte(arg, i)) - end - return bytes - elseif type(arg) == "number" then - local bytes = {} - while arg > 0 do - table.insert(bytes, 1, arg % 256) - arg = math.floor(arg / 256) - end - return bytes - elseif type(arg) == "table" then - return arg -- Assuming it's already a bytearray table - else - error("Invalid argument type for bytearray()") - end - end, - - -- bytes() - bytes = function (arg) -- bytes - if type(arg) == "string" then - local bytes = {} - for i = 1, #arg do - table.insert(bytes, string.byte(arg, i)) - end - return bytes - elseif type(arg) == "table" then - return arg -- Assuming it's already a bytes table - else - error("Invalid argument type for bytes()") - end - end, - - -- compile() - compile = loadstring, - - - -- help() - help = function (object) -- help - -- This is a placeholder implementation and might not cover all possible use cases. - -- You would need to provide your own implementation based on your specific requirements. - -- Here's an example of displaying a help message for an object: - print("Help for object:", object) - print("Type:", type(object)) - print("Learn more in the official roblox documentation!") - end, - - -- memoryview() - memoryview = function (object) -- memoryview - -- This is a placeholder implementation and might not cover all possible use cases. - -- You would need to provide your own implementation based on your specific requirements. - -- Here's an example of creating a memory view object: - if type(object) == "table" then - local buffer = table.concat(object) - return { buffer = buffer, itemsize = 1 } - else - error("Invalid argument type for memoryview()") - end - end, - -- repr() - repr = function (object) -- repr - -- This is a placeholder implementation and might not cover all possible use cases. - -- You would need to provide your own implementation based on your specific requirements. - -- Here's an example of generating a representation of an object: - return tostring(object) - end, - - -- sorted() - sorted = function (iterable, cmp, key, reverse) -- sorted - -- This is a placeholder implementation and might not cover all possible use cases. - -- You would need to provide your own implementation based on your specific requirements. - -- Here's an example of sorting an iterable table: - local sortedTable = {} - for key, value in pairs(iterable) do - table.insert(sortedTable, { key = key, value = value }) - end - table.sort(sortedTable, function(a, b) - -- Compare logic based on cmp, key, reverse parameters - return a.key < b.key - end) - local i = 0 - return function() - i = i + 1 - local entry = sortedTable[i] - if entry then - return entry.key, entry.value - end - end - end, - - -- vars() - vars = function (object) -- vars - -- This is a placeholder implementation and might not cover all possible use cases. - -- You would need to provide your own implementation based on your specific requirements. - -- Here's an example of getting the attributes of an object: - local attributes = {} - for key, value in pairs(object) do - attributes[key] = value - end - return attributes - end, - - __import__ = require, - - formatmod = function (left, right) - if type(left) == "string" then - return string.format(left, right) - elseif type(left) == "table" then - local result = {} - for i, v in ipairs(left) do - result[i] = string.format(v, right) - end - return result - elseif type(left) == "number" then - return math.fmod(left, right) - else - error("Invalid argument type for %") - end - end, - - safeadd = function(left, right) - if type(left) ~= type(right) then - error("Cannot add values of different types") - end - local chosentype = type(left) - if chosentype == "string" then - return left .. right - elseif chosentype == "number" then - return left + right - elseif chosentype == "table" then - local result = {} - for i, v in ipairs(left) do - table.insert(result, v) - end - for i, v in ipairs(right) do - table.insert(result, v) - end - return result - elseif chosentype == "function" then - return function(...) - left(...) - right(...) - end - else - error("Invalid argument type for +") - end - end - } - - for i, v in items do - items[i] = wrap(v) - end - for i, v in language do - items[i] = wrap(getfenv()[i]) - end - return items -end -function fromFileImport(scriptin) - if scriptin == nil then error("Cannot import from nil.") end - if scriptin:IsA("ModuleScript") then - return require(scriptin) - else - return _G.pyc.data[scriptin] or error("Cannot import from script, it is not a module script and is not registered in _G") - end -end -local import = function(inscript) return function(index, sub) -- import - -- IMPORT METHODS: - -- Local libraries table - Added - -- _G.pyc.data[script], will return all of its return values, for non modulescripts - Added in fromFileImport - -- require(script), for modulescripts - Added in fromFileImport - -- (require/_G.pyc.data).Contents, for open, dont worry about this one - Added in open - -- Index is ., look for the script/module script from inscript's parent - Added - -- Index is /, look inside of inscript - Added - -- Index is . look for sub inside of inscripts parent - Added - -- Index is / look for sub inside of inscript - Added - -- Search in dependencies folder, dependencies folder should have a script called "content" use fromFileImport and that will have all of the dependencies - Added - - - if index == "." then - if sub then - return fromFileImport(inscript.Parent:FindFirstChild(sub)) - end - elseif index == "/" then - if sub then - return fromFileImport(inscript:FindFirstChild(sub)) - end - elseif index:sub(1,1) == "." then - if sub then - return fromFileImport(inscript.Parent:FindFirstChild(index:sub(2)))[sub] - end - elseif index:sub(1,1) == "/" then - if sub then - return fromFileImport(inscript:FindFirstChild(index:sub(2)))[sub] - end - elseif libraries[index] then -- Local libraries table - if sub then - return libraries[index][sub] - end - return libraries[index] - else - local dependencies = fromFileImport(dependenciesfolder:FindFirstChild("content")).Contents -- works just like open - if dependencies[index] then - if sub then - return dependencies[index][sub] - end - return dependencies[index] - end - end -end end -local include = function() - error("C and C++ are not complete yet") -end - -local module = function(scriptname) - return { - py = { - import(scriptname), - pythonBuiltIn(scriptname) - }, - lunar = { - import(scriptname), - {-- lunar built in: NOTHING - }, - }, - c = { - include, - {-- c and c++ built in - } - } - } -end - - - -_G.pyc = module -_G.pyc.libs = {} \ No newline at end of file diff --git a/robloxpyc/model.py b/robloxpyc/model.py deleted file mode 100644 index 4db8c5c..0000000 --- a/robloxpyc/model.py +++ /dev/null @@ -1,1718 +0,0 @@ -########################################################################### -# Data model -# -# This is a transitional AST structure; it defines an object model that -# is structured like C++, but outputs Python. At the top of the tree is -# a Module definition. -########################################################################### -from __future__ import unicode_literals, print_function - -import sys - -from collections import OrderedDict - -from clang.cindex import TypeKind - -# Python 2 compatibility shims -if sys.version_info.major <= 2: - text = unicode -else: - text = str - - -__all__ = ( - 'CONSUMED', 'UNDEFINED', - 'Module', - 'Enumeration', 'EnumValue', - 'Function', 'Parameter', 'Variable', - 'Typedef', - 'Class', 'Struct', 'Union', - 'Attribute', 'Constructor', 'Destructor', 'Method', - 'Return', 'Block', 'If', 'Do', 'While', 'For', - 'Break', 'Continue', - 'VariableReference', 'TypeReference', 'PrimitiveTypeReference', 'AttributeReference', 'SelfReference', - 'Literal', 'ListLiteral', - 'UnaryOperation', 'BinaryOperation', 'ConditionalOperation', - 'Parentheses', 'ArraySubscript', - 'Cast', 'Invoke', 'New', -) - - -# A marker for token use during macro expansion -CONSUMED = object() - -# A marker for unknown values -UNDEFINED = object() - - -class Expression(object): - # An expression is the left node of the AST. Operations, - # literals, and references to attributes/members are all - # expresisons. Expressions don't have context - def __repr__(self): - return "<%s>" % (self.__class__.__name__) - - def clean_argument(self): - return self - - -class Declaration(Expression): - # A Declaration is a named expression. As they are named, - # They must belong to a context; that context provides the - # scope in which the declaration is valid. - # An anonymous declaration is a declaration without a - # discoverable name. - def __init__(self, context, name): - self._name = None - - self.context = context - self.name = name - - def __repr__(self): - try: - return "<%s %s>" % (self.__class__.__name__, self.full_name) - except: - return "<%s %s>" % (self.__class__.__name__, self.name) - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - # If there has been a change of name (usually due to an anonymous - # declaration being typedef'd) make sure the name dictionary is - # updated to reflect the new name. - if self.context and self._name: - del self.context.names[self._name] - - self._name = value - - if self.context and value: - self.context.names[value] = self - - @property - def full_name(self): - if self.context: - return '::'.join([self.context.full_name, self.name]) - return self.name - - @property - def root(self): - if self.context is None: - return self - else: - return self.context.root - - -class Context(Declaration): - # A context is a scope in for declaration names. Contexts - # are heirarchical - the can be part of other contexts. - # There can also be related contexts; these are alternate - # sources of names. - def __init__(self, context, name): - super(Context, self).__init__(context=context, name=name) - self.names = OrderedDict() - self.related_contexts = set() - - def __getitem__(self, name): - return self.__getitem(name, set()) - - def __getitem(self, name, looked): - if self in looked: - raise KeyError(name) - - looked.add(self) - - # The name we're looking for might be annotated with - # const, class, or any number of other descriptors. - # Remove them, and then remove any extra spaces so that - # we're left with a compact type name. - name = name.replace('const', '') - name = name.replace('class', '') - name = name.replace('virtual', '') - name = name.replace(' ', '') - - # If the name is scoped, do a lookup from the root node. - # Otherwise, just look up the name in the current context. - if '::' in name: - parts = name.split('::') - # print("LOOK FOR NAME", parts) - decl = self.root - for part in parts: - decl = decl[part] - return decl - else: - try: - # print("LOOK FOR NAME PART", name, "in", self.name, '->', self.names) - return self.names[name] - except KeyError: - if self.context: - try: - return self.context.__getitem(name, looked) - except KeyError: - pass - - for related in self.related_contexts: - # print("LOOK FOR NAME PART IN RELATED NAMESPACE", related) - try: - return related.__getitem(name, looked) - except KeyError: - pass - - raise - - -########################################################################### -# Modules -########################################################################### - -class Module(Context): - def __init__(self, name, context=None): - super(Module, self).__init__(context=context, name=name) - self.declarations = [] - self.classes = set() - - self.imports = {} - self.submodules = {} - self.module = self - self.using = None - - @property - def is_module(self): - return True - - def add_to_context(self, context): - context.add_submodule(self) - - def add_class(self, klass): - if klass not in self.classes: - self.declarations.append(klass) - self.classes.add(klass) - klass.add_imports(self) - - def add_struct(self, struct): - if struct not in self.classes: - self.declarations.append(struct) - self.classes.add(struct) - struct.add_imports(self) - - def add_union(self, union): - if union not in self.classes: - self.declarations.append(union) - self.classes.add(union) - union.add_imports(self) - - def add_function(self, function): - self.declarations.append(function) - function.add_imports(self) - - def add_enumeration(self, enum): - self.declarations.append(enum) - enum.add_imports(self) - - def add_class_attribute(self, attr): - # Class attributes might be added to this context because of - # the way they're declared, but they actually belong to - # the context in which they're declared (which should be - # a child of *this* module). - attr.context.add_class_attribute(attr) - attr.add_imports(self) - - def add_attribute(self, attr): - # Attributes might be added to this context because of - # the way they're declared, but they actually belong to - # the context in which they're declared (which should be - # a child of *this* module). - attr.context.add_attribute(attr) - attr.add_imports(self) - - def add_variable(self, var): - self.declarations.append(var) - var.add_imports(self) - - def add_statement(self, statement): - self.declarations.append(statement) - statement.add_imports(self) - - def add_import(self, path, symbol=None): - self.imports.setdefault(path, set()).add(symbol) - - def add_imports(self, context): - pass - - def add_submodule(self, module): - self.submodules[module.name] = module - - def add_using_decl(self, decl): - if not self.using: - self.using = Context(None, 'using-placeholder') - self.related_contexts.add(self.using) - - self.using.names[decl.name] = decl - - def output(self, out): - if self.imports: - for path in sorted(self.imports): - if self.imports[path]: - out.write('from %s import %s' % ( - path, - ', '.join(sorted(self.imports[path])) - )) - else: - out.write('import %s' % path) - out.clear_line() - - out.clear_major_block() - for decl in self.declarations: - # Ignore symbols that are known to be internal. - if self.context is None and decl.name in ( - 'ptrdiff_t', 'max_align_t', 'va_list', '__gnuc_va_list' - ): - continue - out.clear_minor_block() - decl.output(out) - out.clear_line() - - -########################################################################### -# Parent -########################################################################### - -class Parent(Context): - # Parent is a base class for all contexts that aren't modules. - def __init__(self, context, name): - super(Parent, self).__init__(context=context, name=name) - self.names = OrderedDict() - - @property - def module(self): - "Return the name of the module that contains the declaration of this type" - context = self.context - while not context.is_module: - context = context.context - return context - - @property - def module_name(self): - """Return the fully qualified name of this type within the module. - - For example, given: - - class Foo: - class Bar: - pass - - - class Foo has a module name of "Foo" - class Bar has a module name of "Foo.Bar" - """ - if not self.name: - return - - mod_name_parts = [self.name] - context = self.context - while not context.is_module: - mod_name_parts.append(context.name) - context = context.context - - # The module name is the name required to get to a declaration - # inside a module. - mod_name_parts.reverse() - return '.'.join(mod_name_parts) - - @property - def import_name(self): - """Return the name that must be imported to get access to this node. - - For example, given: - - class Foo: - class Bar: - pass - - the import name for both Foo and Bar is "Foo". - """ - if not self.name: - return - - context = self - while not context.context.is_module: - context = context.context - - return context.name - - @property - def is_module(self): - return False - - -########################################################################### -# Enumerated types -########################################################################### - -class Enumeration(Parent): - def __init__(self, context, name): - super(Enumeration, self).__init__(context=context, name=name) - self.enumerators = [] - - def add_enumerator(self, enumerator): - self.enumerators.append(enumerator) - self.context.names[enumerator.name] = enumerator - enumerator.enumeration = self - - def add_to_context(self, context): - context.add_enumeration(self) - - def add_imports(self, context): - context.module.add_import('enum', 'Enum') - - def output(self, out): - out.clear_major_block() - out.write("class %s(Enum):" % self.name) - out.start_block() - if self.enumerators: - for enumerator in self.enumerators: - out.clear_line() - out.write("%s = %s" % ( - enumerator.name, enumerator.value - )) - else: - out.clear_line() - out.write('pass') - out.end_block() - out.clear_major_block() - - -class EnumValue(Declaration): - # A value in an enumeration. - # EnumValues are slightly odd, becaues they are Declarations - # in the same context as the Enumeration they belong to. - def __init__(self, context, name, value): - super(EnumValue, self).__init__(context, name) - self.name = name - self.value = value - self.enumeration = None - - def add_imports(self, context): - if context.module != self.context.module: - context.module.add_import( - self.context.module.full_name.replace('::', '.'), - self.context.name - ) - - def output(self, out): - out.write('%s.%s' % (self.enumeration.module_name, self.name)) - - -########################################################################### -# Functions -########################################################################### - -class Function(Parent): - def __init__(self, context, name): - super(Function, self).__init__(context=context, name=name) - self.parameters = [] - self.statements = None - - def add_parameter(self, parameter): - self.parameters.append(parameter) - - def add_to_context(self, context): - context.add_function(self) - - def add_import(self, scope, name): - self.context.add_import(scope, name) - - def add_imports(self, context): - for param in self.parameters: - param.add_imports(context) - - def add_statement(self, statement): - self.statements.append(statement) - statement.add_imports(self) - - def output(self, out): - out.clear_major_block() - out.write('def %s(' % self.name) - for i, param in enumerate(self.parameters): - if i != 0: - out.write(', ') - param.output(out) - out.write('):') - out.start_block() - if self.statements: - for statement in self.statements: - out.clear_line() - statement.output(out) - else: - out.clear_line() - out.write('pass') - out.end_block() - out.clear_major_block() - - -class Parameter(Declaration): - def __init__(self, function, name, ctype, default): - super(Parameter, self).__init__(context=function, name=name) - self.ctype = ctype - self.default = default - - @property - def module_name(self): - return self.name - - def add_to_context(self, context): - context.add_parameter(self) - - def add_imports(self, context): - if self.default is not UNDEFINED and self.default is not None: - self.default.add_imports(context) - - def output(self, out): - out.write(self.name) - if self.default is None: - out.write('=None') - elif self.default is not UNDEFINED: - out.write('=') - self.default.output(out) - - -class Variable(Declaration): - def __init__(self, context, name, value): - super(Variable, self).__init__(context=context, name=name) - self.value = value - - @property - def module_name(self): - return self.name - - def add_to_context(self, context): - context.add_variable(self) - - def add_imports(self, context): - if self.value and self.value is not UNDEFINED: - self.value.add_imports(context) - - def output(self, out): - if self.value is not UNDEFINED: - out.write('%s = ' % self.name.replace('::', '.')) - if self.value: - self.value.output(out) - else: - out.write('None') - out.clear_line() - - -class Typedef(Declaration): - def __init__(self, context, name, typ): - super(Typedef, self).__init__(context=context, name=name) - self.type = typ - - @property - def module(self): - return self.context.module - - @property - def module_name(self): - return self.name - - def add_to_context(self, context): - context.add_variable(self) - - def add_imports(self, context): - self.type.add_imports(context) - - def output(self, out): - out.write('%s = ' % self.name) - self.type.output(out) - out.clear_line() - - -########################################################################### -# Structs -########################################################################### - -class Struct(Parent): - def __init__(self, context, name): - super(Struct, self).__init__(context=context, name=name) - self._superclass = None - self.constructors = {} - self.destructor = None - self.class_attributes = OrderedDict() - self.attributes = OrderedDict() - self.methods = OrderedDict() - self.classes = OrderedDict() - - @property - def superclass(self): - return self._superclass - - @superclass.setter - def superclass(self, ref): - ref.add_imports(self) - self._superclass = ref.type - self.related_contexts.add(ref.type) - - def add_imports(self, context): - for constructor in self.constructors.values(): - constructor.add_imports(context) - - for attr in self.class_attributes.values(): - attr.add_imports(context) - - for attr in self.attributes.values(): - attr.add_imports(context) - - for klass in self.classes.values(): - klass.add_imports(context) - - for method in self.methods.values(): - method.add_imports(context) - - def add_class(self, klass): - self.classes[klass.name] = klass - - def add_struct(self, struct): - self.classes[struct.name] = struct - - def add_union(self, union): - self.classes[union.name] = union - - def add_constructor(self, method): - print("Ignoring constructor for struct %s" % self.name, file=sys.stderr) - - def add_destructor(self, method): - if self.destructor: - if self.destructor.statements is None: - self.destructor = method - else: - raise Exception("Cannot handle multiple desructors") - else: - self.destructor = method - - def add_class_attribute(self, attr): - self.class_attributes[attr.name] = attr - - def add_attribute(self, attr): - self.attributes[attr.name] = attr - - def add_method(self, method): - self.methods[method.name] = method - - def add_variable(self, var): - self.class_attributes[var.name] = var - - def add_to_context(self, context): - context.add_struct(self) - - def output(self, out): - out.clear_major_block() - if self.superclass: - out.write("class %s(%s):" % (self.name, self.superclass.module_name)) - else: - out.write("class %s:" % self.name) - out.start_block() - - if self.class_attributes or self.attributes or self.destructor or self.classes or self.methods: - if self.class_attributes: - for name, variable in self.class_attributes.items(): - out.clear_line() - variable.output(out) - out.clear_minor_block() - - if self.attributes: - out.clear_line() - params = ''.join(', %s=None' % name for name in self.attributes.keys()) - out.write('def __init__(self%s):' % params) - out.start_block() - for name, attr in self.attributes.items(): - out.clear_line() - attr.output(out, init=True) - out.end_block() - - if self.destructor: - self.destructor.output(out) - - for name, klass in self.classes.items(): - klass.output(out) - - for name, method in self.methods.items(): - method.output(out) - else: - out.clear_line() - out.write('pass') - out.end_block() - out.clear_major_block() - - -########################################################################### -# Unions -########################################################################### - -class Union(Parent): - def __init__(self, context, name): - super(Union, self).__init__(context=context, name=name) - self._superclass = None - self.class_attributes = OrderedDict() - self.attributes = OrderedDict() - self.enumerations = OrderedDict() - self.methods = OrderedDict() - self.classes = OrderedDict() - - @property - def superclass(self): - return self._superclass - - @superclass.setter - def superclass(self, ref): - ref.add_imports(self) - self._superclass = ref.type - self.related_contexts.add(ref.type) - - def add_imports(self, context): - for attr in self.class_attributes.values(): - attr.add_imports(context) - - for attr in self.attributes.values(): - attr.add_imports(context) - - for klass in self.classes.values(): - klass.add_imports(context) - - for method in self.methods.values(): - method.add_imports(context) - - def add_class(self, klass): - self.classes[klass.name] = klass - - def add_struct(self, struct): - self.classes[struct.name] = struct - - def add_union(self, union): - self.classes[union.name] = union - - def add_class_attribute(self, var): - self.class_attributes[var.name] = var - - def add_attribute(self, attr): - self.attributes[attr.name] = attr - - def add_enumeration(self, enum): - self.enumerations[enum.name] = enum - - def add_method(self, method): - self.methods[method.name] = method - - def add_to_context(self, context): - context.add_union(self) - - def output(self, out): - out.clear_major_block() - out.write("class %s:" % self.name) - out.start_block() - if self.class_attributes or self.attributes or self.classes or self.methods: - if self.class_attributes: - for name, variable in self.class_attributes.items(): - out.clear_line() - variable.output(out) - out.clear_minor_block() - - if self.attributes: - params = ''.join(', %s=None' % name for name in self.attributes.keys()) - out.clear_line() - out.write('def __init__(self%s):' % params) - out.start_block() - for name, attr in self.attributes.items(): - out.clear_line() - attr.output(out, init=True) - out.end_block() - - for name, enum in self.enumerations.items(): - enum.output(out) - - for name, klass in self.classes.items(): - klass.output(out) - - for name, method in self.methods.items(): - method.output(out) - else: - out.clear_line() - out.write('pass') - - out.end_block() - out.end_block() - out.clear_major_block() - - -########################################################################### -# Classes -########################################################################### - -class Class(Parent): - def __init__(self, context, name): - super(Class, self).__init__(context=context, name=name) - self._superclass = None - self.constructors = {} - self.destructor = None - self.class_attributes = OrderedDict() - self.attributes = OrderedDict() - self.enumerations = OrderedDict() - self.methods = OrderedDict() - self.classes = OrderedDict() - - @property - def superclass(self): - return self._superclass - - @superclass.setter - def superclass(self, ref): - ref.add_imports(self) - self._superclass = ref.type - self.related_contexts.add(ref.type) - - def add_imports(self, context): - for constructor in self.constructors.values(): - constructor.add_imports(context) - - for attr in self.class_attributes.values(): - attr.add_imports(context) - - for attr in self.attributes.values(): - attr.add_imports(context) - - for enum in self.enumerations.values(): - enum.add_imports(context) - - for klass in self.classes.values(): - klass.add_imports(context) - - for method in self.methods.values(): - method.add_imports(context) - - def add_class(self, klass): - self.classes[klass.name] = klass - - def add_struct(self, struct): - self.classes[struct.name] = struct - - def add_union(self, union): - self.classes[union.name] = union - - def add_constructor(self, method): - signature = tuple(p.ctype for p in method.parameters) - self.constructors[signature] = method - - if len(self.constructors) > 1: - print("Multiple constructors for class %s (adding [%s])" % ( - self.name, - ','.join(s for s in signature), - ), - file=sys.stderr - ) - - def add_destructor(self, method): - if self.destructor: - if self.destructor.statements is None: - self.destructor = method - else: - raise Exception("Cannot handle multiple desructors") - else: - self.destructor = method - - def add_class_attribute(self, var): - self.class_attributes[var.name] = var - - def add_attribute(self, attr): - self.attributes[attr.name] = attr - - def add_method(self, method): - self.methods[method.name] = method - - def add_enumeration(self, enum): - self.enumerations[enum.name] = enum - - def add_variable(self, var): - self.class_attributes[var.name] = var - - def add_to_context(self, context): - context.add_class(self) - - def output(self, out): - out.clear_major_block() - if self.superclass: - out.write("class %s(%s):" % (self.name, self.superclass.module_name)) - else: - out.write("class %s:" % self.name) - out.start_block() - if self.class_attributes or self.attributes or self.constructors or self.destructor or self.enumerations or self.classes or self.methods: - if self.class_attributes: - for name, variable in self.class_attributes.items(): - out.clear_line() - variable.output(out) - out.clear_minor_block() - - for signature, constructor in sorted(self.constructors.items()): - constructor.output(out) - - if self.destructor: - self.destructor.output(out) - - for name, enum in self.enumerations.items(): - enum.output(out) - - for name, klass in self.classes.items(): - klass.output(out) - - for name, method in self.methods.items(): - method.output(out) - else: - out.clear_line() - out.write('pass') - out.end_block() - out.clear_major_block() - - -########################################################################### -# Class/Struct/Union components -########################################################################### - -class Attribute(Declaration): - def __init__(self, klass, name, value=None, static=False): - super(Attribute, self).__init__(context=klass, name=name) - self.value = value - self.static = static - - @property - def module(self): - return self.context.module - - @property - def module_name(self): - return self.context.name + '.' + self.name - - def add_to_context(self, context): - if self.static: - context.add_class_attribute(self) - else: - context.add_attribute(self) - - def add_imports(self, context): - if self.value: - self.value.add_imports(context) - - def output(self, out, init=False): - if not self.static: - out.write('self.') - out.write('%s = ' % self.name) - if init: - if self.value: - out.write('%s if %s else ' % (self.name, self.name)) - self.value.output(out) - else: - out.write(self.name) - else: - if self.value: - self.value.output(out) - else: - out.write('None') - out.clear_line() - - -class Constructor(Parent): - def __init__(self, klass): - super(Constructor, self).__init__(context=klass, name=None) - self.parameters = [] - self.statements = [] - - def __repr__(self): - return '' % self.context.full_name - - def add_parameter(self, parameter): - self.parameters.append(parameter) - - def add_to_context(self, klass): - self.context.add_constructor(self) - - def add_attribute(self, attr): - self.context.add_attribute(attr) - - def add_imports(self, context): - for param in self.parameters: - param.add_imports(context) - - def add_statement(self, statement): - self.statements.append(statement) - statement.add_imports(self.context) - - def output(self, out): - out.clear_minor_block() - out.write("def __init__(self") - if self.parameters: - for param in self.parameters: - out.write(', ') - param.output(out) - out.write('):') - out.start_block() - if self.context.attributes or self.statements: - has_init = False - for name, attr in self.context.attributes.items(): - if attr.value is not None: - out.clear_line() - attr.output(out) - has_init = True - - if self.statements: - for statement in self.statements: - out.clear_line() - statement.output(out) - elif not has_init: - out.clear_line() - out.write('pass') - - else: - out.clear_line() - out.write('pass') - out.end_block() - - -class Destructor(Parent): - def __init__(self, klass): - super(Destructor, self).__init__(context=klass, name=None) - self.parameters = [] - self.statements = None - - def add_to_context(self, klass): - self.context.add_destructor(self) - - def add_imports(self, context): - pass - - def add_statement(self, statement): - if self.statements: - self.statements.append(statement) - else: - self.statements = [statement] - statement.add_imports(self.context) - - def output(self, out): - out.clear_minor_block() - out.write("def __del__(self):") - out.start_block() - if self.statements: - for statement in self.statements: - out.clear_line() - statement.output(out) - else: - out.clear_line() - out.write('pass') - out.end_block() - - -class Method(Parent): - def __init__(self, klass, name, pure_virtual, static): - super(Method, self).__init__(context=klass, name=name) - self.parameters = [] - self.statements = None - self.pure_virtual = pure_virtual - self.static = static - - def add_parameter(self, parameter): - self.parameters.append(parameter) - - def add_to_context(self, context): - self.context.add_method(self) - - def add_imports(self, context): - for param in self.parameters: - param.add_imports(context) - - if self.statements: - for statement in self.statements: - statement.add_imports(context) - - def add_statement(self, statement): - if self.statements: - self.statements.append(statement) - else: - self.statements = [statement] - statement.add_imports(self.context) - - def output(self, out): - out.clear_minor_block() - if self.static: - out.write("@staticmethod") - out.clear_line() - out.write('def %s(' % self.name) - else: - out.write('def %s(self' % self.name) - - for i, param in enumerate(self.parameters): - if i != 0 or not self.static: - out.write(', ') - param.output(out) - out.write('):') - - out.start_block() - if self.statements: - for statement in self.statements: - out.clear_line() - statement.output(out) - elif self.pure_virtual: - out.clear_line() - out.write('raise NotImplementedError()') - else: - out.clear_line() - out.write('pass') - out.end_block() - - -########################################################################### -# Statements -########################################################################### - -class Block(Parent): - def __init__(self, context): - super(Block, self).__init__(context=context, name=None) - self.statements = [] - - def __repr__(self): - return '' - - def add_statement(self, statement): - self.statements.append(statement) - - def add_imports(self, context): - for statement in self.statements: - statement.add_imports(context) - - def output(self, out): - out.start_block() - if self.statements: - for statement in self.statements: - out.clear_line() - statement.output(out) - else: - out.clear_line() - out.write('pass') - out.end_block() - - -class Return(Expression): - def __init__(self): - self.value = None - - def add_imports(self, context): - if self.value: - self.value.add_imports(context) - - def add_expression(self, expr): - self.value = expr - - def output(self, out): - out.write('return') - if self.value: - out.write(' ') - self.value.output(out) - out.clear_line() - - -class If(Parent): - def __init__(self, condition, context): - super(If, self).__init__(context, name=None) - self.condition = condition - self.if_true = Block(self) - self.if_false = None - - def __repr__(self): - return '' % self.condition - - def add_imports(self, context): - self.condition.add_imports(context) - self.if_true.add_imports(context) - if self.if_false: - self.if_false.add_imports(context) - - def output(self, out, is_elif=False): - out.clear_line() - out.write('elif ' if is_elif else 'if ') - self.condition.output(out) - out.write(':') - - self.if_true.output(out) - - if self.if_false is not None: - if isinstance(self.if_false, If): - self.if_false.output(out, is_elif=True) - else: - out.clear_line() - out.write('else:') - if isinstance(self.if_false, Block): - self.if_false.output(out) - else: - out.clear_line() - out.start_block() - self.if_false.output(out) - out.end_block() - - -class Do(Parent): - def __init__(self, context): - super(Do, self).__init__(context, name=None) - self.condition = None - self.statements = Block(self) - - def __repr__(self): - return '' % self.condition - - def add_imports(self, context): - self.condition.add_imports(context) - self.statements.add_imports(context) - - def output(self, out): - out.clear_line() - out.write('while True:') - - if self.statements.statements: - self.statements.output(out) - - out.clear_line() - out.start_block() - out.write('if not (') # invert the condition - self.condition.output(out) - out.write('):') - - out.start_block() - out.clear_line() - out.write('break') - out.end_block() - out.end_block() - - out.end_block() - -class While(Parent): - def __init__(self, condition, context): - super(While, self).__init__(context, name=None) - self.condition = condition - self.statements = Block(self) - - def __repr__(self): - return '' % self.condition - - def add_imports(self, context): - self.condition.add_imports(context) - self.statements.add_imports(context) - - def output(self, out): - out.clear_line() - out.write('while ') - self.condition.output(out) - out.write(':') - - self.statements.output(out) - - -class For(Parent): - def __init__(self, init_stmt, expr_stmt, end_expr, context): - super(For, self).__init__(context, name=None) - self.init_stmt = init_stmt - self.expr_stmt = expr_stmt - self.end_expr = end_expr - self.statements = Block(self) - - def __repr__(self): - return '' % self.condition - - def add_imports(self, context): - if self.init_stmt: - self.init_stmt.add_imports(context) - if self.expr_stmt: - self.expr_stmt.add_imports(context) - if self.end_expr: - self.end_expr.add_imports(context) - - self.statements.add_imports(context) - - def output(self, out): - out.clear_line() - # TODO: convert simple expressions to a range statement - - if self.init_stmt: - self.init_stmt.output(out) - - if self.expr_stmt: - out.write('while ') - self.expr_stmt.output(out) - out.write(':') - else: - out.write('while True:') - - # suppress the extra pass - if self.statements.statements or not self.end_expr: - self.statements.output(out) - - if self.end_expr: - out.start_block() - out.clear_line() - self.end_expr.output(out) - out.end_block() - -class Break(object): - - def add_imports(self, context): - pass - - def output(self, out): - out.clear_line() - out.write('break') - out.clear_line() - - -class Continue(object): - - def __init__(self, end_expr): - self.end_expr = end_expr - - def add_imports(self, context): - pass - - def output(self, out): - out.clear_line() - # this exists for when a continue is used inside of a for - # loop that has an incrementing expression in it - if self.end_expr: - self.end_expr.output(out) - out.clear_line() - out.write('continue') - out.clear_line() - -########################################################################### -# References to variables and types -########################################################################### - -# A reference to a variable -class VariableReference(Expression): - def __init__(self, var, node): - self.var = var - self.node = node - - @property - def name(self): - return self.var.name - - @property - def module(self): - return self.var.context.module - - @property - def module_name(self): - return self.var.module_name - - @property - def import_name(self): - return self.var.module_name - - def add_imports(self, context): - # If the type being referenced isn't from the same module - # then an import will be required. - if context.module != self.module: - context.module.add_import( - self.module.full_name.replace('::', '.'), - self.import_name - ) - - def output(self, out): - out.write(self.module_name) - - -# A reference to a type -class TypeReference(Expression): - def __init__(self, typ): - self.type = typ - - @property - def name(self): - return self.type.name - - @property - def module(self): - return self.type.context.module - - @property - def module_name(self): - return self.type.module_name - - @property - def import_name(self): - return self.type.import_name - - def __repr__(self): - return '' % self.type - - def add_imports(self, context): - # If the type being referenced isn't from the same module - # then an import will be required. - if context.module != self.type.module: - context.module.add_import( - self.type.module.full_name.replace('::', '.'), - self.import_name - ) - - def output(self, out): - out.write(self.module_name) - - -# A reference to a primitive type -class PrimitiveTypeReference(Expression): - def __init__(self, name): - self.name = name - - def add_imports(self, context): - pass - - def output(self, out): - out.write(self.name) - - -# A reference to self. -class SelfReference(Expression): - def add_imports(self, context): - pass - - def output(self, out): - out.write('self') - - -# A reference to an attribute on a class -class AttributeReference(Expression): - def __init__(self, instance, attr): - self.instance = instance - self.name = attr - - # def add_to_context(self, context): - # pass - - def add_imports(self, context): - self.instance.add_imports(context) - - def output(self, out): - self.instance.output(out) - out.write('.%s' % self.name) - - -########################################################################### -# Literals -########################################################################### - -class Literal(Expression): - def __init__(self, value): - self.value = value - - def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, self.value) - - def add_imports(self, context): - pass - - def output(self, out): - out.write(text(self.value)) - - -class ListLiteral(Expression): - def __init__(self): - self.value = [] - - def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, self.value) - - def add_imports(self, context): - for value in self.value: - value.add_imports(context) - - def append(self, item): - self.value.append(item) - - def output(self, out): - out.write('[') - for i, item in enumerate(self.value): - if i != 0: - out.write(', ') - item.output(out) - out.write(']') - - -########################################################################### -# Expressions -########################################################################### - -class UnaryOperation(Expression): - def __init__(self, op, value): - self.name = op - self.value = value - - def add_imports(self, context): - self.value.add_imports(context) - - def output(self, out, depth=0): - out.write(' ' * depth) - python_op = { - '!': 'not ', - '~': '~', - }.get(self.name, self.name) - - # while this will often end up with incorrect python, - # better than silently failing on ++/-- (which don't do - # anything in python) - if python_op == '++': - self.value.output(out) - out.write(' += 1') - elif python_op == '--': - out.write(python_op) - out.write(' -= 1') - else: - out.write(python_op) - self.value.output(out) - - def clean_argument(self): - # Strip dereferencing operators - if self.name == '&': - return self.value.clean_argument() - elif self.name == '*': - return self.value.clean_argument() - else: - return self - - -class BinaryOperation(Expression): - def __init__(self, lvalue, op, rvalue): - self.lvalue = lvalue - self.name = op - self.rvalue = rvalue - - def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, self.name) - - def add_imports(self, context): - self.lvalue.add_imports(context) - self.rvalue.add_imports(context) - - def add_to_context(self, context): - context.add_statement(self) - - def output(self, out, depth=0): - self.lvalue.output(out) - python_op = { - # Equality - '=': ' = ', - - # Arithmetic - '+': ' + ', - '-': ' - ', - '*': ' * ', - '/': ' / ', - '%': ' % ', - - # Comparison - '==': ' == ', - '!=': ' != ', - '>': ' > ', - '<': ' < ', - '>=': ' >= ', - '<=': ' <= ', - - # Bitwise - '&': ' & ', - '|': ' | ', - '^': ' ^ ', - '<<': ' << ', - '>>': ' >> ', - - # Assignment - '+=': ' += ', - '-=': ' -= ', - '*=': ' *= ', - '/=': ' /= ', - '%=': ' %= ', - - '&=': ' &= ', - '|=': ' |= ', - '^=': ' ^= ', - '<<=': ' <<= ', - '>>=': ' >>= ', - - # Logical - '&&': ' and ', - '||': ' or ', - - }.get(self.name, self.name) - - out.write(python_op) - self.rvalue.output(out) - - -class ConditionalOperation(Expression): - def __init__(self, condition, true_result, false_result): - self.condition = condition - self.true_result = true_result - self.false_result = false_result - - def add_imports(self, context): - self.condition.add_imports(context) - self.true_result.add_imports(context) - self.false_result.add_imports(context) - - def output(self, out): - self.true_result.output(out) - out.write(' if ') - self.condition.output(out) - out.write(' else ') - self.false_result.output(out) - - -class Parentheses(Expression): - def __init__(self, body): - self.body = body - - def add_imports(self, context): - self.body.add_imports(context) - - def output(self, out): - if isinstance(self.body, (BinaryOperation, ConditionalOperation)): - out.write('(') - self.body.output(out) - out.write(')') - else: - self.body.output(out) - - -class ArraySubscript(Expression): - def __init__(self, value, index): - self.value = value - self.index = index - - def add_imports(self, context): - self.value.add_imports(context) - self.index.add_imports(context) - - def output(self, out): - self.value.output(out) - out.write('[') - self.index.output(out) - out.write(']') - - def clean_argument(self): - return self - - -class Cast(Expression): - def __init__(self, typekind, value): - self.typekind = typekind - self.value = value - - def __repr__(self): - return "" % self.typekind - - def add_imports(self, context): - self.value.add_imports(context) - - def output(self, out): - # Primitive types are cast using Python casting. - # Other types are passed through as ducks. - if self.typekind == TypeKind.BOOL: - out.write('bool(') - self.value.output(out) - out.write(')') - elif self.typekind in ( - TypeKind.CHAR_U, - TypeKind.UCHAR, - TypeKind.CHAR16, - TypeKind.CHAR32, - TypeKind.CHAR_S, - TypeKind.SCHAR, - TypeKind.WCHAR, - ): - out.write('str(') - self.value.output(out) - out.write(')') - elif self.typekind in ( - TypeKind.USHORT, - TypeKind.UINT, - TypeKind.ULONG, - TypeKind.ULONGLONG, - TypeKind.UINT128, - TypeKind.SHORT, - TypeKind.INT, - TypeKind.LONG, - TypeKind.LONGLONG, - TypeKind.INT128, - ): - out.write('int(') - self.value.output(out) - out.write(')') - elif self.typekind in ( - TypeKind.FLOAT, - TypeKind.DOUBLE, - TypeKind.LONGDOUBLE - ): - out.write('float(') - self.value.output(out) - out.write(')') - else: - self.value.output(out) - - def clean_argument(self): - return self.value - - -class Invoke(Expression): - def __init__(self, fn): - self.fn = fn - self.arguments = [] - - def __repr__(self): - return "" % self.fn - - def add_argument(self, argument): - self.arguments.append(argument) - - def add_imports(self, context): - self.fn.add_imports(context) - for arg in self.arguments: - arg.add_imports(context) - - def output(self, out): - self.fn.output(out) - out.write('(') - if self.arguments: - self.arguments[0].output(out) - for arg in self.arguments[1:]: - out.write(', ') - arg.output(out) - out.write(')') - - -class New(Expression): - def __init__(self, typeref): - self.typeref = typeref - self.arguments = [] - - def __repr__(self): - return "" % self.typeref - - def add_argument(self, argument): - self.arguments.append(argument) - - def add_imports(self, context): - self.typeref.add_imports(context) - for arg in self.arguments: - arg.add_imports(context) - - def output(self, out): - self.typeref.output(out) - out.write('(') - if self.arguments: - self.arguments[0].output(out) - for arg in self.arguments[1:]: - out.write(', ') - arg.output(out) - out.write(')') \ No newline at end of file diff --git a/robloxpyc/nameconstdesc.py b/robloxpyc/nameconstdesc.py deleted file mode 100644 index ac95186..0000000 --- a/robloxpyc/nameconstdesc.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Name constant description""" - - -class NameConstantDesc: - """Name constant description""" - - NAME = { - None: "nil", - True: "true", - False: "false", - } diff --git a/robloxpyc/nodevisitor.py b/robloxpyc/nodevisitor.py deleted file mode 100644 index 56efe6f..0000000 --- a/robloxpyc/nodevisitor.py +++ /dev/null @@ -1,967 +0,0 @@ -"""Node visitor""" -import ast, sys - -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from binopdesc import BinaryOperationDesc - from boolopdesc import BooleanOperationDesc - from cmpopdesc import CompareOperationDesc - from nameconstdesc import NameConstantDesc - from unaryopdesc import UnaryOperationDesc - - from context import Context - from loopcounter import LoopCounter - from tokenendmode import TokenEndMode - from colortext import * -else: - from .binopdesc import BinaryOperationDesc - from .boolopdesc import BooleanOperationDesc - from .cmpopdesc import CompareOperationDesc - from .nameconstdesc import NameConstantDesc - from .unaryopdesc import UnaryOperationDesc - - from .context import Context - from .loopcounter import LoopCounter - from .tokenendmode import TokenEndMode - from .colortext import * - -class NodeVisitor(ast.NodeVisitor): - LUACODE = "[[lua]]" - - """Node visitor""" - def __init__(self, context=None, config=None): - self.context = context if context is not None else Context() - self.config = config - self.last_end_mode = TokenEndMode.LINE_FEED - self.output = [] - - def visit_Assign(self, node): - """Visit assign""" - target = self.visit_all(node.targets[0], inline=True) - value = self.visit_all(node.value, inline=True) - - local_keyword = "" - - last_ctx = self.context.last() - - if last_ctx["class_name"]: - target = ".".join([last_ctx["class_name"], target]) - - if ("." not in target) and (not last_ctx["locals"].exists(target)) and ("[" not in target) and ("(" not in target): - local_keyword = "local " - last_ctx["locals"].add_symbol(target) - - - self.emit("{local}{target} = {value}".format(local=local_keyword, - target=target, - value=value)) - - ### MATCHES ### - def visit_Match(self, node): - """Visit match""" - self.emit("match({0}, ".format(self.visit_all(node.subject, inline=True))+"{") - for case in node.cases: - if hasattr(case.pattern, "value"): - self.emit("[{0}] = function()".format(case.pattern.value.s)) - self.visit_all(case.body) - self.emit("end,") - else: - self.emit("[\"default\"] = function()") - self.visit_all(case.body) - self.emit("end,") - self.emit("})") - # example input: - # match x: - # case "10": - # print("x is 10") - # case "20": - # print("x is 20") - # case _: - # print("x is not 10 or 20") - # example output: - # match(x, { - # ["10"] = function() - # print("x is 10") - # end, - # ["20"] = function() - # print("x is 20") - # end, - # ["_"] = function() - # print("x is not 10 or 20") - # end - # }) - - def visit_MatchValue(self, node): - """Visit match value""" - return self.visit_all(node.value, inline=True) - - def visit_MatchCase(self, node): - """Visit match case""" - return self.visit_all(node.body) - - def visit_MatchPattern(self, node): - """Visit match pattern""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchSingleton(self, node): - """Visit match singleton""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchSequence(self, node): - """Visit match sequence""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchMapping(self, node): - """Visit match mapping""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchClass(self, node): - """Visit match class""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchAs(self, node): - """Visit match as""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchKeyword(self, node): - """Visit match keyword""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchStar(self, node): - """Visit match star""" - return self.visit_all(node.pattern, inline=True) - - def visit_MatchOr(self, node): - """Visit match or""" - return self.visit_all(node.pattern, inline=True) - - ### END MATCH ### - def visit_AnnAssign(self, node): - """Visit annassign""" - target = self.visit_all(node.target, inline=True) - value = self.visit_all(node.value, inline=True) - - local_keyword = "" - - last_ctx = self.context.last() - - if last_ctx["class_name"]: - target = ".".join([last_ctx["class_name"], target]) - - if "." not in target and not last_ctx["locals"].exists(target): - local_keyword = "local " - last_ctx["locals"].add_symbol(target) - - self.emit("{local}{target} = {value}".format(local=local_keyword, - target=target, - value=value, - type=self.visit_all(node.annotation, inline=True))) - # example input: - # a: int = 1 - # example output: - # local a = 1 - - def visit_AugAssign(self, node): - """Visit augassign""" - operation = BinaryOperationDesc.OPERATION[node.op.__class__] - - target = self.visit_all(node.target, inline=True) - - values = { - "left": target, - "right": self.visit_all(node.value, inline=True), - "operation": operation["value"], - } - - line = "({})".format(operation["format"]) - line = line.format(**values) - - self.emit("{target} = {line}".format(target=target, line=line)) - - def visit_Attribute(self, node): - """Visit attribute""" - line = "{object}.{attr}" - values = { - "object": self.visit_all(node.value, True), - "attr": node.attr, - } - self.emit(line.format(**values)) - - def visit_BinOp(self, node): - """Visit binary operation""" - operation = BinaryOperationDesc.OPERATION[node.op.__class__] - format = "" - if "format" in operation: - format = operation["format"] - else: - format = operation["function"](node.left, node.right) - line = "({})".format(format) - values = { - "left": self.visit_all(node.left, True), - "right": self.visit_all(node.right, True), - "operation": operation["value"], - } - self.emit(line.format(**values)) - - def visit_BoolOp(self, node): - """Visit boolean operation""" - operation = BooleanOperationDesc.OPERATION[node.op.__class__] - line = "({})".format(operation["format"]) - values = { - "left": self.visit_all(node.values[0], True), - "right": self.visit_all(node.values[1], True), - "operation": operation["value"], - } - - self.emit(line.format(**values)) - - def visit_Break(self, node): - """Visit break""" - self.emit("break") - - def visit_AsyncWith(self, node): - """Visit async with""" - """Visit with""" - self.emit("coroutine.wrap(function()") - - self.visit_all(node.body) - - body = self.output[-1] - lines = [] - for i in node.items: - line = "" - if i.optional_vars is not None: - line = "local {} = " - line = line.format(self.visit_all(i.optional_vars, - inline=True)) - line += self.visit_all(i.context_expr, inline=True) - lines.append(line) - - for line in lines: - body.insert(0, line) - - self.emit("end)()") - - def visit_Await(self, node): - """Visit await""" - self.emit("coroutine.yield({})".format(self.visit_all(node.value, True))) - - def visit_Slice(self, node): - """Visit slice""" - print(yellow("warning", ["bold"])+" syntax based slicing is not supported yet. Use slice(, , , ) instead. This node will not be translated.") - - - def visit_JoinedStr(self, node): - """Visit joined string""" - values = [self.visit_all(value, True) for value in node.values] - self.emit('.'.join(values)) - - def visit_Bytes(self, node): - """Visit bytes""" - #remove first letter from string - self.emit(str(node.s)[1:]) - - def visit_Try(self, node): - """Visit try""" - self.emit("local success, result = pcall(function()") - self.visit_all(node.body) - self.emit("end)") - - def visit_TryStar(self, node): - """Visit try""" - self.emit("local success, result = pcall(function()") - self.visit_all(node.body) - self.emit("end)") - - def visit_ImportFrom(self, node): - """Visit import from""" - module = node.module - if module is None: - module = "" - else: - module = module - - for name in node.names: - if name.asname is None: - self.emit("local {name} = import(\"{module}\", \"{name}\")".format( - name=name.name, - module=module, - )) - else: - if name.name == "*": - print("roblox-pyc: Importing all from a module is not supported yet. Issues will occur.") - self.emit("local {name} = import(\"{module}\", \"{realname}\")".format( - name=name.asname, - module=module, - realname=name.name, - )) - - def visit_Assert(self, node): - """Visit assert""" - self.emit("assert({})".format(self.visit_all(node.test, True))) - - def visit_Nonlocal(self, node): - """Visit nonlocal""" - for name in node.names: - self.context.last()["nonlocals"].add_symbol(name) - - - def visit_ExceptHandler(self, node): - """Visit except handler""" - self.emit("if not success then") - self.emit("local "+node.name + " = result") - self.visit_all(node.body) - self.emit("end") - - def visit_AsyncFunctionDef(self, node): - """Visit async function definition""" - line = "{local}{name} = asynchronousfunction(function({arguments})" - - last_ctx = self.context.last() - - name = node.name - if last_ctx["class_name"]: - name = ".".join([last_ctx["class_name"], name]) - - arguments = [arg.arg for arg in node.args.args] - - if node.args.vararg is not None: - arguments.append("...") - - local_keyword = "" - - if "." not in name and not last_ctx["locals"].exists(name): - local_keyword = "local " - last_ctx["locals"].add_symbol(name) - - function_def = line.format(local=local_keyword, - name=name, - arguments=", ".join(arguments)) - - self.emit(function_def) - - self.context.push({"class_name": ""}) - self.visit_all(node.body) - self.context.pop() - - body = self.output[-1] - - if node.args.vararg is not None: - line = "local {name} = list {{...}}".format(name=node.args.vararg.arg) - body.insert(0, line) - - arg_index = -1 - for i in reversed(node.args.defaults): - line = "{name} = {name} or {value}" - - arg = node.args.args[arg_index] - values = { - "name": arg.arg, - "value": self.visit_all(i, inline=True), - } - body.insert(0, line.format(**values)) - - arg_index -= 1 - - self.emit("end)") - - for decorator in reversed(node.decorator_list): - decorator_name = self.visit_all(decorator, inline=True) - values = { - "name": name, - "decorator": decorator_name, - } - line = "{name} = {decorator}({name})".format(**values) - self.emit(line) - def visit_AsyncFor(self, node): - """Visit async for""" - line = "asynchronousfunction(function() for {target} in {iter} do" - values = { - "target": self.visit_all(node.target, True), - "iter": self.visit_all(node.iter, True), - } - self.emit(line.format(**values)) - self.visit_all(node.body) - self.emit("end end)") - - def visit_Raise(self, node): - """Visit raise""" - self.emit("error(" + self.visit_all(node.exc, True) + ")") - - def visit_FormattedValue(self, node): - """Visit formatted value""" - if node.format_spec is None: - return self.visit_all(node.value, True) - else: - return self.visit_all(node.value, True) + ":" + self.visit_all(node.format_spec, True) - - def visit_Set(self, node): - """Visit set""" - values = [self.visit_all(value, True) for value in node.elts] - self.emit('{' + ', '.join(values) + '}') - - def visit_Call(self, node): - """Visit function call""" - line = "{name}({arguments})" - - name = self.visit_all(node.func, inline=True) - arguments = [self.visit_all(arg, inline=True) for arg in node.args] - - self.emit(line.format(name=name, arguments=", ".join(arguments))) - - def visit_ClassDef(self, node): - """Visit class definition""" - bases = [self.visit_all(base, inline=True) for base in node.bases] - - local_keyword = "" - last_ctx = self.context.last() - if not last_ctx["class_name"] and not last_ctx["locals"].exists(node.name): - local_keyword = "local " - last_ctx["locals"].add_symbol(node.name) - - name = node.name - if last_ctx["class_name"]: - name = ".".join([last_ctx["class_name"], name]) - - values = { - "local": local_keyword, - "name": name, - "node_name": node.name, - } - - self.emit("{local}{name} = class(function({node_name})".format(**values)) - - self.context.push({"class_name": node.name}) - self.visit_all(node.body) - self.context.pop() - - self.output[-1].append("return {node_name}".format(**values)) - - self.emit("end, {{{}}})".format(", ".join(bases))) - - # Return class object only in the top-level classes. - # Not in the nested classes. - if self.config["class"]["return_at_the_end"] and not last_ctx["class_name"]: - self.emit("return {}".format(name)) - - def visit_Compare(self, node): - """Visit compare""" - - line = "" - - left = self.visit_all(node.left, inline=True) - for i in range(len(node.ops)): - operation = node.ops[i] - operation = CompareOperationDesc.OPERATION[operation.__class__] - - right = self.visit_all(node.comparators[i], inline=True) - - values = { - "left": left, - "right": right, - } - - if isinstance(operation, str): - values["op"] = operation - line += "{left} {op} {right}".format(**values) - elif isinstance(operation, dict): - line += operation["format"].format(**values) - - if i < len(node.ops) - 1: - left = right - line += " and " - - self.emit("({})".format(line)) - - def visit_Continue(self, node): - """Visit continue""" - last_ctx = self.context.last() - line = "continue" - self.emit(line) - - def visit_Delete(self, node): - """Visit delete""" - targets = [self.visit_all(target, inline=True) for target in node.targets] - nils = ["nil" for _ in targets] - line = "{targets} = {nils}".format(targets=", ".join(targets), - nils=", ".join(nils)) - self.emit(line) - - def visit_Dict(self, node): - """Visit dictionary""" - keys = [] - - for key in node.keys: - value = self.visit_all(key, inline=True) - if isinstance(key, ast.Str): - value = "[{}]".format(value) - keys.append(value) - - values = [self.visit_all(item, inline=True) for item in node.values] - - elements = ["{} = {}".format(keys[i], values[i]) for i in range(len(keys))] - elements = ", ".join(elements) - self.emit("dict {{{}}}".format(elements)) - - def visit_DictComp(self, node): - """Visit dictionary comprehension""" - self.emit("(function()") - self.emit("local result = dict {}") - - ends_count = 0 - - for comp in node.generators: - line = "for {target} in {iterator} do" - values = { - "target": self.visit_all(comp.target, inline=True), - "iterator": self.visit_all(comp.iter, inline=True), - } - line = line.format(**values) - self.emit(line) - ends_count += 1 - - for if_ in comp.ifs: - line = "if {} then".format(self.visit_all(if_, inline=True)) - self.emit(line) - ends_count += 1 - - line = "result[{key}] = {value}" - values = { - "key": self.visit_all(node.key, inline=True), - "value": self.visit_all(node.value, inline=True), - } - self.emit(line.format(**values)) - - self.emit(" ".join(["end"] * ends_count)) - - self.emit("return result") - self.emit("end)()") - - def visit_Ellipsis(self, node): - """Visit ellipsis""" - self.emit("...") - - def visit_Expr(self, node): - """Visit expr""" - expr_is_docstring = False - if isinstance(node.value, ast.Str): - expr_is_docstring = True - - self.context.push({"docstring": expr_is_docstring}) - output = self.visit_all(node.value) - self.context.pop() - - self.output.append(output) - - def visit_FunctionDef(self, node): - """Visit function definition""" - line = "{local}function {name}({arguments})" - - last_ctx = self.context.last() - - name = node.name - if last_ctx["class_name"]: - name = ".".join([last_ctx["class_name"], name]) - - arguments = [arg.arg for arg in node.args.args] - - if node.args.vararg is not None: - arguments.append("...") - - local_keyword = "" - - if "." not in name and not last_ctx["locals"].exists(name): - local_keyword = "local " - last_ctx["locals"].add_symbol(name) - - function_def = line.format(local=local_keyword, - name=name, - arguments=", ".join(arguments)) - - self.emit(function_def) - - self.context.push({"class_name": ""}) - self.visit_all(node.body) - self.context.pop() - - body = self.output[-1] - - if node.args.vararg is not None: - line = "local {name} = list {{...}}".format(name=node.args.vararg.arg) - body.insert(0, line) - - arg_index = -1 - for i in reversed(node.args.defaults): - line = "{name} = {name} or {value}" - - arg = node.args.args[arg_index] - values = { - "name": arg.arg, - "value": self.visit_all(i, inline=True), - } - body.insert(0, line.format(**values)) - - arg_index -= 1 - - self.emit("end") - - for decorator in reversed(node.decorator_list): - decorator_name = self.visit_all(decorator, inline=True) - values = { - "name": name, - "decorator": decorator_name, - } - line = "{name} = {decorator}({name})".format(**values) - self.emit(line) - - def visit_For(self, node): - """Visit for loop""" - line = "for {target} in {iter} do" - - values = { - "target": self.visit_all(node.target, inline=True), - "iter": self.visit_all(node.iter, inline=True), - } - - self.emit(line.format(**values)) - - continue_label = LoopCounter.get_next() - self.context.push({ - "loop_label_name": continue_label, - }) - self.visit_all(node.body) - self.context.pop() - - #self.output[-1].append("::{}::".format(continue_label)) - - self.emit("end") - def visit_Global(self, node): - """Visit globals""" - last_ctx = self.context.last() - for name in node.names: - last_ctx["globals"].add_symbol(name) - - def visit_If(self, node): - """Visit if""" - test = self.visit_all(node.test, inline=True) - - line = "if {} then".format(test) - - self.emit(line) - self.visit_all(node.body) - - if node.orelse: - if isinstance(node.orelse[0], ast.If): - elseif = node.orelse[0] - elseif_test = self.visit_all(elseif.test, inline=True) - - line = "elseif {} then".format(elseif_test) - self.emit(line) - - output_length = len(self.output) - self.visit_If(node.orelse[0]) - - del self.output[output_length] - del self.output[-1] - else: - self.emit("else") - self.visit_all(node.orelse) - - self.emit("end") - - def visit_IfExp(self, node): - """Visit if expression""" - line = "{cond} and {true_cond} or {false_cond}" - values = { - "cond": self.visit_all(node.test, inline=True), - "true_cond": self.visit_all(node.body, inline=True), - "false_cond": self.visit_all(node.orelse, inline=True), - } - - self.emit(line.format(**values)) - - def visit_Import(self, node): - """Visit import""" - line = 'local {asname} = import("{name}")' - values = {"asname": "", "name": ""} - - if node.names[0].asname is None: - values["name"] = node.names[0].name - values["asname"] = values["name"] - values["asname"] = values["asname"].split(".")[-1] - else: - values["asname"] = node.names[0].asname - values["name"] = node.names[0].name - - self.emit(line.format(**values)) - - def visit_Index(self, node): - """Visit index""" - self.emit(self.visit_all(node.value, inline=True)) - - def visit_Lambda(self, node): - """Visit lambda""" - line = "function({arguments}) return" - - arguments = [arg.arg for arg in node.args.args] - - function_def = line.format(arguments=", ".join(arguments)) - - output = [] - output.append(function_def) - output.append(self.visit_all(node.body, inline=True)) - output.append("end") - - self.emit(" ".join(output)) - - def visit_List(self, node): - """Visit list""" - elements = [self.visit_all(item, inline=True) for item in node.elts] - line = "list {{{}}}".format(", ".join(elements)) - self.emit(line) - - def visit_ListComp(self, node): - """Visit list comprehension""" - self.emit("(function()") - self.emit("local result = list {}") - - ends_count = 0 - - for comp in node.generators: - line = "for {target} in {iterator} do" - values = { - "target": self.visit_all(comp.target, inline=True), - "iterator": self.visit_all(comp.iter, inline=True), - } - line = line.format(**values) - self.emit(line) - ends_count += 1 - - for if_ in comp.ifs: - line = "if {} then".format(self.visit_all(if_, inline=True)) - self.emit(line) - ends_count += 1 - - line = "result.append({})" - line = line.format(self.visit_all(node.elt, inline=True)) - self.emit(line) - - self.emit(" ".join(["end"] * ends_count)) - - self.emit("return result") - self.emit("end)()") - - def visit_Module(self, node): - """Visit module""" - self.visit_all(node.body) - self.output = self.output[0] - - def visit_Name(self, node): - """Visit name""" - self.emit(node.id) - - def visit_NameConstant(self, node): - """Visit name constant""" - self.emit(NameConstantDesc.NAME[node.value]) - - def visit_Num(self, node): - """Visit number""" - self.emit(str(node.n)) - - def visit_Pass(self, node): - """Visit pass""" - pass - - def visit_Return(self, node): - """Visit return""" - line = "return " - line += self.visit_all(node.value, inline=True) - self.emit(line) - - def visit_Starred(self, node): - """Visit starred object""" - value = self.visit_all(node.value, inline=True) - line = "unpack({})".format(value) - self.emit(line) - - def visit_Str(self, node): - """Visit str""" - value = node.s - if value.startswith(NodeVisitor.LUACODE): - value = value[len(NodeVisitor.LUACODE):] - self.emit(value) - elif self.context.last()["docstring"]: - self.emit('--[[ {} ]]'.format(node.s)) - else: - # Add to context - self.emit('"{}"'.format(node.s)) - - def visit_Subscript(self, node): - """Visit subscript""" - line = "{name}[{index}]" - values = { - "name": self.visit_all(node.value, inline=True), - "index": self.visit_all(node.slice, inline=True), - } - # append to context - ##self.context.last()["subscript"] = node - - self.emit(line.format(**values)) - - def visit_Tuple(self, node): - """Visit tuple""" - elements = [self.visit_all(item, inline=True) for item in node.elts] - self.emit(", ".join(elements)) - - def visit_UnaryOp(self, node): - """Visit unary operator""" - operation = UnaryOperationDesc.OPERATION[node.op.__class__] - value = self.visit_all(node.operand, inline=True) - - line = operation["format"] - values = { - "value": value, - "operation": operation["value"], - } - - self.emit(line.format(**values)) - - def visit_While(self, node): - """Visit while""" - test = self.visit_all(node.test, inline=True) - - self.emit("while {} do".format(test)) - - continue_label = LoopCounter.get_next() - self.context.push({ - "loop_label_name": continue_label, - }) - self.visit_all(node.body) - self.context.pop() - - #self.output[-1].append("::{}::".format(continue_label)) - - self.emit("end") - - def visit_Yield(self, node): - """Visit yield""" - self.emit("coroutine.yield({})".format(self.visit_all(node.value, True))) - def visit_GeneratorExp(self, node): - """Visit generator expression""" - self.emit("(function()") - self.emit("local result = list {}") - - ends_count = 0 - - for comp in node.generators: - line = "for {target} in {iterator} do" - values = { - "target": self.visit_all(comp.target, inline=True), - "iterator": self.visit_all(comp.iter, inline=True), - } - line = line.format(**values) - self.emit(line) - ends_count += 1 - - for if_ in comp.ifs: - line = "if {} then".format(self.visit_all(if_, inline=True)) - self.emit(line) - ends_count += 1 - - line = "result.append({})" - line = line.format(self.visit_all(node.elt, inline=True)) - self.emit(line) - - self.emit(" ".join(["end"] * ends_count)) - - self.emit("return result") - self.emit("end)()") - def visit_YieldFrom(self, node): - """Visit yield from""" - self.emit("coroutine.yield({})".format(self.visit_all(node.value, True))) - def visit_With(self, node): - """Visit with""" - self.emit("do") - - self.visit_all(node.body) - - body = self.output[-1] - lines = [] - for i in node.items: - line = "" - if i.optional_vars is not None: - line = "local {} = " - line = line.format(self.visit_all(i.optional_vars, - inline=True)) - line += self.visit_all(i.context_expr, inline=True) - lines.append(line) - - for line in lines: - body.insert(0, line) - - self.emit("end") - def visit_SetComp(self, node): - """Visit set comprehension""" - self.emit("(function()") - self.emit("local result = set {}") - - ends_count = 0 - - for comp in node.generators: - line = "for {target} in {iterator} do" - values = { - "target": self.visit_all(comp.target, inline=True), - "iterator": self.visit_all(comp.iter, inline=True), - } - line = line.format(**values) - self.emit(line) - ends_count += 1 - - for if_ in comp.ifs: - line = "if {} then".format(self.visit_all(if_, inline=True)) - self.emit(line) - ends_count += 1 - - line = "result.add({})" - line = line.format(self.visit_all(node.elt, inline=True)) - self.emit(line) - - self.emit(" ".join(["end"] * ends_count)) - - self.emit("return result") - self.emit("end)()") - def generic_visit(self, node): - """Unknown nodes handler""" - if node is None: - return - raise RuntimeError("{} is unsupported".format(node)) - - def visit_all(self, nodes, inline=False): - """Visit all nodes in the given list""" - - if not inline: - last_ctx = self.context.last() - last_ctx["locals"].push() - - visitor = NodeVisitor(context=self.context, config=self.config) - - if isinstance(nodes, list): - for node in nodes: - visitor.visit(node) - if not inline: - self.output.append(visitor.output) - else: - visitor.visit(nodes) - if not inline: - self.output.extend(visitor.output) - - if not inline: - last_ctx = self.context.last() - last_ctx["locals"].pop() - - if inline: - return " ".join(visitor.output) - - def emit(self, value): - """Add translated value to the output""" - self.output.append(value) diff --git a/robloxpyc/parser.py b/robloxpyc/parser.py deleted file mode 100644 index ee7f2bf..0000000 --- a/robloxpyc/parser.py +++ /dev/null @@ -1,1711 +0,0 @@ -########################################################################### -# Code Parser -# -# This uses the clang Python API to parse and traverse the AST for C++ -# code, producing a data model. -########################################################################### -from __future__ import unicode_literals, print_function - -import argparse -import os -import re -import sys - -from clang.cindex import ( - CursorKind, - Index, - StorageClass, - TranslationUnit, - TypeKind, - Config, -) - -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from model import * - from writer import CodeWriter -else: - from .model import * - from .writer import CodeWriter - - -# Python 2 compatibility shims -if sys.version_info.major <= 2: - text = unicode -else: - text = str - - -class BaseParser(object): - def __init__(self): - self.index = Index.create() - - def diagnostics(self, out): - for diag in self.tu.diagnostics: - print('%s %s (line %s, col %s) %s' % ( - { - 4: 'FATAL', - 3: 'ERROR', - 2: 'WARNING', - 1: 'NOTE', - 0: 'IGNORED', - }[diag.severity], - diag.location.file, - diag.location.line, - diag.location.column, - diag.spelling - ), file=out) - - -class CodeConverter(BaseParser): - def __init__(self, name, dylib, verbosity=0): - if dylib != 'None': - #print("Setting dylib to %s" % dylib) - Config.set_library_file(dylib) - super(CodeConverter, self).__init__() - # Tools for debugging. - self.verbosity = verbosity - self._depth = 0 - - self.root_module = Module(name) - self.filenames = set() - self.macros = {} - self.instantiated_macros = {} - - self.ignored_files = set() - self.last_decl = [] - - self.namespace = self.root_module - - def output(self, module, out): - module_path = module.split('.') - - mod = None - for i, mod_name in enumerate(module_path): - if mod is None: - mod = self.root_module - else: - mod = mod.submodules[mod_name] - - if mod_name != mod.name: - raise Exception("Unknown module '%s'" % '.'.join(module_path[:i+1])) - - if mod: - mod.output(CodeWriter(out)) - else: - raise Exception('No module name specified') - - def _output_module(self, mod, out): - out.write('===== %s.py ==================================================\n' % mod.full_name) - mod.output(CodeWriter(out)) - for submodule in mod.submodules.values(): - self._output_module(submodule, out) - - - def output_all(self, out): - self._output_module(self.root_module, out) - - def parse(self, filenames, flags): - abs_filenames = [os.path.abspath(f) for f in filenames] - self.filenames.update(abs_filenames) - - for filename in abs_filenames: - if os.path.splitext(filename)[1] != '.h': - self.tu = self.index.parse( - filename, - args=flags, - options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD - ) - self.handle(self.tu.cursor, self.root_module) - - def parse_text(self, content, flags): - for f, c in content: - abs_filename = os.path.abspath(f) - self.filenames.add(abs_filename) - - self.tu = self.index.parse( - f, - args=flags, - unsaved_files=[(f, c)], - options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD - ) - self.handle(self.tu.cursor, self.root_module) - - def localize_namespace(self, namespace): - """Strip any namespace parts that are implied by the current namespace. - - This takes into account the current namespace, and any `using` - declarations that are currently in effect. - """ - namespace = self.root_module.full_name + '::' + namespace.strip('::') - - # Strip the current namespace or using prefix - # if there is an overlap. - if namespace.startswith(self.namespace.full_name): - namespace = namespace[len(self.namespace.full_name) + 2:] - #else: - #for using_namespace in self.using: - # # TODO: handle USING statements. - # pass - - # If there's still a namespace, add a separator - # so it can prefixed onto the name to be used. - if namespace: - namespace += "::" - - return namespace - - def lookup(self, children, context): - """Utility function to lookup a namespaced object""" - child = next(children) - names = [] - try: - while child.kind == CursorKind.NAMESPACE_REF: - names.append(child.spelling) - child = next(children) - except StopIteration: - child = None - - if names: - context = self.root_module['::'.join(names)] - - return child, context - - - def handle(self, node, context=None): - if (node.location.file is None - or os.path.abspath(node.location.file.name) in self.filenames): - try: - if ((node.location.file or node.kind == CursorKind.TRANSLATION_UNIT) and self.verbosity > 0 - or node.location.file is None and self.verbosity > 1): - debug = [ - ' ' * self._depth, - context, - node.kind, - '(type:%s | result type:%s)' % (node.type.kind, node.result_type.kind), - node.spelling, - node.location.file - ] - if self.verbosity > 1: - debug.extend([ - '[line %s:%s%s-%s]' % ( - node.extent.start.line, node.extent.start.column, - ('line %s:' % node.extent.end.line) - if node.extent.start.line != node.extent.end.line - else '', - node.extent.end.column), - ]) - if self.verbosity > 2: - debug.extend([ - [t.spelling for t in node.get_tokens()] - ]) - print(*debug) - - handler = getattr(self, 'handle_%s' % node.kind.name.lower()) - - except AttributeError: - print( - "Ignoring node of type %s (%s)" % ( - node.kind, - ' '.join( - t.spelling for t in node.get_tokens()) - ), - file=sys.stderr - ) - handler = None - else: - if node.location.file.name.startswith('/usr/include'): - min_level = 2 - elif node.location.file.name.startswith('/usr/local'): - min_level = 2 - else: - min_level = 1 - - if node.location.file.name not in self.ignored_files: - if self.verbosity >= min_level: - print("Ignoring node in file %s" % node.location.file) - self.ignored_files.add(node.location.file.name) - handler = None - - if handler: - self._depth += 1 - result = handler(node, context) - self._depth -= 1 - - # Some definitions might be part of an inline typdef. - # Keep a track of the last type defined, just in case - # it needs to be referenced as part of a typedef. - if node.kind.name.lower() in ( - 'struct_decl', - 'union_decl', - ): - self.last_decl = result - else: - self.last_decl = None - - return result - - def handle_unexposed_decl(self, node, context): - # Ignore unexposed declarations (e.g., friend qualifiers) - pass - - def handle_struct_decl(self, node, context): - # If a struct is pre-declared, use the existing declaration, - # rather than overwriting the old one. - try: - struct = context[node.spelling] - except KeyError: - struct = Struct(context, node.spelling) - - for child in node.get_children(): - decl = self.handle(child, struct) - if decl: - decl.add_to_context(struct) - return struct - - def handle_union_decl(self, node, context): - # If a union is pre-declared, use the existing declaration, - # rather than overwriting the old one. - try: - union = context[node.spelling] - except KeyError: - union = Union(context, node.spelling) - - for child in node.get_children(): - decl = self.handle(child, union) - if decl: - decl.add_to_context(union) - return union - - def handle_class_decl(self, node, context): - # If a class is pre-declared, use the existing declaration, - # rather than overwriting the old one. - try: - klass = context[node.spelling] - except KeyError: - klass = Class(context, node.spelling) - - # To avoid forward declaration issues, run two passes - # over the class. - # - # The first pass picks up any names that might be referred - # to by inline methods (enums, fields, etc) - for child in node.get_children(): - if child.type.kind != TypeKind.FUNCTIONPROTO: - # Handle enums and fields first - decl = self.handle(child, klass) - if decl: - decl.add_to_context(klass) - - # The second pass parses the methods. - for child in node.get_children(): - if child.type.kind == TypeKind.FUNCTIONPROTO: - decl = self.handle(child, klass) - if decl: - decl.add_to_context(klass) - return klass - - def handle_enum_decl(self, node, context): - enum = Enumeration(context, node.spelling) - for child in node.get_children(): - enum.add_enumerator(self.handle(child, enum)) - return enum - - def handle_field_decl(self, node, context): - try: - is_static = node.storage_class == StorageClass.STATIC - - children = node.get_children() - child = next(children) - if child.kind == CursorKind.TYPE_REF: - value = None - else: - value = self.handle(child, context) - - # If the node is of type CONSTANTARRAY, then the field - # is an array; set the value to a tuple of that size. - # Otherwise, ignore the value; You need to be at C++11 - # to be using that feature, anyway. - if node.type.kind == TypeKind.CONSTANTARRAY: - value = Literal(text(tuple(None for i in range(0, int(value.value))))) - else: - value = None - - attr = Attribute(context, node.spelling, value=value, static=is_static) - except StopIteration: - attr = Attribute(context, node.spelling, value=None, static=is_static) - - # A field decl will have param children if the field - # is a function pointer. However, we don't care about - # the arguments; Python will duck type any call. - - return attr - - def handle_enum_constant_decl(self, node, context): - return EnumValue(context, node.spelling, node.enum_value) - - def handle_function_decl(self, node, context): - function = Function(context, node.spelling) - try: - # print("FUNCTION DECL") - children = node.get_children() - child = next(children) - - # If the node has any children, the first children will be the - # return type and namespace for the function declaration. These - # nodes can be ignored. - # print("FIRST CHILD", child.kind) - while child.kind == CursorKind.NAMESPACE_REF: - child = next(children) - # print("NS CHILD", child.kind) - while child.kind == CursorKind.TYPE_REF: - child = next(children) - # print("TYPE REF CHILD", child.kind) - - # Subsequent nodes will be the parameters for the function. - try: - while True: - decl = self.handle(child, function) - if decl: - decl.add_to_context(function) - child = next(children) - except StopIteration: - pass - - except StopIteration: - pass - - # Only return a node if we get function definition. The prototype - # can be ignored. - if function.statements is not None: - return function - - def handle_var_decl(self, node, context): - try: - # print("VAR DECL") - children = node.get_children() - prev_child = None - child = next(children) - # print("FIRST CHILD", child.kind) - - # If there are children, the first children will define the - # namespace and type for the variable being declared (or the context - # for the variable in the case of an assignment). Ignore these - # nodes, and go straight to the actual content. - while child.kind == CursorKind.NAMESPACE_REF: - prev_child = child - child = next(children) - # print("NS CHILD", child.kind, child.spelling) - while child.kind == CursorKind.TYPE_REF: - prev_child = child - child = next(children) - # print("TYPE REF CHILD", child.kind, child.spelling) - - # print("FINAL CHILD", child.kind, child.spelling) - # print("NAMESPACE", namespace) - value = self.handle(child, context) - if prev_child and child.type.kind == TypeKind.RECORD and child.kind == CursorKind.INIT_LIST_EXPR: - value = New(TypeReference(context[prev_child.type.spelling])) - for arg in child.get_children(): - value.add_argument(self.handle(arg, context)) - else: - # Array definitions put the array size first. - # If there is a child, discard the value and - # replace it with the list declaration. - try: - value = self.handle(next(children), context) - except StopIteration: - pass - - # If the current context is a module, then we are either defining a - # global variable, or setting a static constant. If the context is a - # class/struct/union, we're defining a static attribute. The typedef - # captured as the initial child nodes tells us the path to the variable - # being set. - if prev_child and isinstance(context, Module): - full_namespace = prev_child.spelling.split()[-1] - decl_context = context[full_namespace] - # print("DECL CONTEXT", decl_context) - namespace = self.localize_namespace(full_namespace) - else: - namespace = '' - decl_context = context - - if isinstance(context, (Class, Struct, Union)): - # print("ATTR DECL with value %s, %s, %s, %s" % (context, namespace, node.spelling, value)) - return Attribute(context, node.spelling, value=value, static=True) - else: - if isinstance(decl_context, (Class, Struct, Union)): - # print("ATTR ASSIGN with value %s, %s, %s, %s" % (context, namespace, node.spelling, value)) - return BinaryOperation( - AttributeReference(TypeReference(decl_context), node.spelling), - '=', value - ) - else: - # print("VAR DECL with value %s, %s, %s, %s" % (context, namespace, node.spelling, value)) - return Variable(decl_context, namespace + node.spelling, value) - - except StopIteration: - # No initial value for the variable. If the context is a module, - # class, struct or union (i.e., high level block structures) - # it still needs to be declared; use a value of None. - if isinstance(context, Module): - # print("VAR DECL no value %s, %s" % (context, node.spelling)) - return Variable(context, node.spelling, value=None) - elif isinstance(context, (Class, Struct, Union)): - # print("ATTR DECL no value %s, %s" % (context, node.spelling)) - is_static = node.storage_class == StorageClass.STATIC - return Attribute(context, node.spelling, value=None, static=is_static) - else: - # print("pre-decl no value %s, %s" % (context, node.spelling)) - return Variable(context, node.spelling, value=UNDEFINED) - - def handle_parm_decl(self, node, function): - try: - children = node.get_children() - child = next(children) - - # If there are any children, this will be a parameter - # with a default value. The children will be the reference - # to the default value. - # If the default value is a non-primitive type, there will - # be NAMESPACE_REF and TYPE_REF nodes; all but the last one - # can be ignored. - - # Any namespace nodes can be stripped - while child.kind in [CursorKind.NAMESPACE_REF, - CursorKind.TYPE_REF, - CursorKind.TEMPLATE_REF]: - child = next(children) - - # If there is a child, it is the default value of the parameter. - value = self.handle(child, function) - except StopIteration: - value = UNDEFINED - - param = Parameter(function, node.spelling, node.type.spelling, value) - - try: - value = self.handle(next(children), function) - raise Exception("Can't handle multiple children on parameter") - except StopIteration: - pass - - return param - - def handle_typedef_decl(self, node, context): - if self.last_decl is None: - c_type_name = node.underlying_typedef_type.spelling - try: - type_ref = PrimitiveTypeReference({ - 'unsigned': 'int', - 'unsigned byte': 'int', - 'unsigned short': 'int', - 'unsigned int': 'int', - 'unsigned long': 'int', - 'unsigned long long': 'int', - 'signed': 'int', - 'short': 'int', - 'long': 'int', - 'int': 'int', - 'long long': 'int', - 'double': 'float', - 'float': 'float', - }[c_type_name]) - except KeyError: - # Remove any template instantiation from the type. - type_name = re.sub('<.*>', '', c_type_name) - type_ref = TypeReference(context[type_name]) - - return Typedef(context, node.spelling, type_ref) - elif self.last_decl.name: - return Typedef(context, node.spelling, TypeReference(context[self.last_decl.name])) - else: - self.last_decl.name = node.spelling - - def handle_cxx_method(self, node, context): - # If this is an inline method, the context will be the - # enclosing class, and the inline declaration will double as the - # prototype. - # - # If it isn't inline, the context will be a module, and the - # prototype will be separate. In this case, the method will - # be found twice - once as the prototype, and once as the - # definition. Parameters are handled as part of the prototype; - # this handle method only returns a new node when it finds the - # prototype. When the body method is encountered, it finds the - # prototype method (which will be the TYPE_REF in the first - # child node), and adds the body definition. - if isinstance(context, (Class, Struct, Union)): - method = Method(context, node.spelling, node.is_pure_virtual_method(), node.is_static_method()) - is_prototype = True - # print("IS PROTOTYPE") - else: - method = None - # print("NOT PROTOTYPE") - is_prototype = False - - children = node.get_children() - try: - prev_child = None - child = next(children) - - # We can ignore override and final attributes on methods. - while child.kind == CursorKind.CXX_OVERRIDE_ATTR: - prev_child = child - child = next(children) - while child.kind == CursorKind.CXX_FINAL_ATTR: - prev_child = child - child = next(children) - - # Then comes the typedef for the return value. - while child.kind in [CursorKind.NAMESPACE_REF, - CursorKind.TYPE_REF, - CursorKind.TEMPLATE_REF]: - prev_child = child - child = next(children) - - if method is None: - ref = self.handle(prev_child, context) - method = ref.type.methods[node.spelling] - - p = 0 - while True: - # print("CHILD", child.kind, child.spelling) - decl = self.handle(child, method) - if decl: - if is_prototype or child.kind != CursorKind.PARM_DECL: - decl.add_to_context(method) - - # Take the parameter names from the implementation version. - if not is_prototype and child.kind == CursorKind.PARM_DECL: - method.parameters[p].name = decl.name - p += 1 - - child = next(children) - except StopIteration: - pass - - # Add a new node for the prototype. Definitions will - # build on the pre-existing node. - if is_prototype: - return method - - def handle_namespace(self, node, module): - # If the namespace already exists, add to it. - anonymous_ns = not node.spelling - if anonymous_ns: - submodule = module - else: - try: - submodule = module.submodules[node.spelling] - except KeyError: - submodule = Module(node.spelling, context=module) - - # Set the current namespace, and clone the current using list. - self.namespace = submodule - #using = self.using.copy() - - # Process the contents of the namespace - for child in node.get_children(): - decl = self.handle(child, submodule) - if decl: - decl.add_to_context(submodule) - - # Restore the previously active namespace and using list. - self.namespace = module - #self.using = using - - if not anonymous_ns: - return submodule - - # def handle_linkage_spec(self, node, context): - - def handle_constructor(self, node, context): - # If this is an inline constructor, the context will be the - # enclosing class, and the inline declaration will double as the - # prototype. - # - # If it isn't inline, the context will be a module, and the - # prototype will be separate. In this case, the constructor will - # be found twice - once as the prototype, and once as the - # definition. Parameters are handled as part of the prototype; - # this handle method only returns a new node when it finds the - # prototype. When the body method is encountered, it finds the - # prototype constructor (which will be the TYPE_REF in the first - # child node), and adds the body definition. - try: - children = node.get_children() - is_prototype = isinstance(context, (Class, Struct)) - if is_prototype: - constructor = Constructor(context) - - child = next(children) - while child.kind == CursorKind.PARM_DECL: - decl = self.handle(child, constructor) - constructor.add_parameter(decl) - child = next(children) - else: - parameters = [] - prev_child = None - child = next(children) - while child.kind == CursorKind.TYPE_REF: - prev_child = child - child = next(children) - - while child.kind == CursorKind.PARM_DECL: - decl = self.handle(child, context) - parameters.append(decl) - child = next(children) - - signature = tuple(p.ctype for p in parameters) - try: - ref = self.handle(prev_child, context) - constructor = ref.type.constructors[signature] - for cp, p in zip(constructor.parameters, parameters): - cp.name = p.name - except KeyError: - raise Exception("No match for constructor %s; options are %s" % ( - signature, ref.type.constructors.keys()) - ) - - member_ref = None - while True: - decl = self.handle(child, constructor) - if decl: - if child.kind == CursorKind.COMPOUND_STMT: - constructor.add_statement(decl) - elif child.kind == CursorKind.MEMBER_REF: - if member_ref is not None: - raise Exception("Unexpected member reference") - member_ref = decl - elif member_ref is not None: - constructor.add_statement( - BinaryOperation(member_ref, '=', decl) - ) - # Reset the member ref. - member_ref = None - elif child.kind not in (CursorKind.PARM_DECL, CursorKind.TYPE_REF): - # Parm decls have - raise Exception("Don't know how to handle %s in constructor." % child.kind) - child = next(children) - except StopIteration: - pass - - # Only add a new node for the prototype. - if is_prototype: - return constructor - - def handle_destructor(self, node, context): - # If this is an inline destructor, the context will be the - # enclosing class, and the inline declaration will double as the - # prototype. - # - # If it isn't inline, the context will be a module, and the - # prototype will be separate. In this case, the destructor will - # be found twice - once as the prototype, and once as the - # definition. Parameters are handled as part of the prototype; - # this handle method only returns a new node when it finds the - # prototype. When the body method is encountered, it finds the - # prototype destructor (which will be the TYPE_REF in the first - # child node), and adds the body definition. - try: - children = node.get_children() - is_prototype = isinstance(context, (Class, Struct)) - if is_prototype: - destructor = Destructor(context) - child = next(children) - else: - prev_child = None - child = next(children) - while child.kind == CursorKind.TYPE_REF: - prev_child = child - child = next(children) - - try: - ref = self.handle(prev_child, context) - destructor = ref.type.destructor - except KeyError: - raise Exception("No destructor declared on class") - - while True: - decl = self.handle(child, destructor) - if decl: - decl.add_to_context(destructor) - child = next(children) - - except StopIteration: - pass - - # Only add a new node for the prototype. - if is_prototype: - return destructor - - # def handle_conversion_function(self, node, context): - - def handle_template_type_parameter(self, node, context): - # Type paramteres can be ignored; templated types are duck typed - pass - - # def handle_template_non_type_parameter(self, node, context): - # def handle_template_template_parameter(self, node, context): - def handle_function_template(self, node, context): - # Treat a function template like any other function declaration. - # Templated types will be duck typed. - if isinstance(context, Class): - return self.handle_cxx_method(node, context) - else: - return self.handle_function_decl(node, context) - - def handle_class_template(self, node, context): - # Treat a class template like any other class declaration. - # Templated types will be duck typed. - return self.handle_class_decl(node, context) - - # def handle_class_template_partial_specialization(self, node, context): - # def handle_namespace_alias(self, node, context): - def handle_using_directive(self, node, context): - child, ns_context = self.lookup(node.get_children(), context) - if child is not None: - # We've got a node that isn't a namespace - raise Exception("Don't know how to handle node of type %s in using directive" % child.kind) - - context.related_contexts.add(ns_context) - - def handle_using_declaration(self, node, context): - children = node.get_children() - child, ns = self.lookup(children, context) - context.add_using_decl(ns[child.spelling]) - - # def handle_type_alias_decl(self, node, context): - - def handle_cxx_access_spec_decl(self, node, context): - # Ignore access specifiers; everything is public. - pass - - def handle_type_ref(self, node, context): - typename = node.spelling.split()[-1] - return TypeReference(context[typename]) - - def handle_cxx_base_specifier(self, node, context): - typename = node.spelling.split()[1] - context.superclass = TypeReference(context[typename]) - - def handle_template_ref(self, node, context): - typename = node.spelling.split()[-1] - return TypeReference(context[typename]) - - def handle_namespace_ref(self, node, context): - pass - - def handle_member_ref(self, node, context): - try: - children = node.get_children() - child = next(children) - ref = AttributeReference(self.handle(child, context), node.spelling) - except StopIteration: - # An implicit reference to `this` - ref = AttributeReference(SelfReference(), node.spelling) - - try: - next(children) - raise Exception("Member reference has > 1 child node.") - except StopIteration: - pass - return ref - - # def handle_label_ref(self, node, context): - # def handle_overloaded_decl_ref(self, node, context): - # def handle_variable_ref(self, node, context): - # def handle_invalid_file(self, node, context): - # def handle_no_decl_found(self, node, context): - # def handle_not_implemented(self, node, context): - # def handle_invalid_code(self, node, context): - - def handle_unexposed_expr(self, node, statement): - # Ignore unexposed nodes; pass whatever is the first - # (and should be only) child unaltered. - try: - children = node.get_children() - expr = self.handle(next(children), statement) - except StopIteration: - return None - - try: - next(children) - raise Exception("Unexposed expression has > 1 children.") - except StopIteration: - pass - - return expr - - def handle_decl_ref_expr(self, node, context): - children = node.get_children() - namespace = '' - try: - child = next(children) - while child.kind == CursorKind.NAMESPACE_REF: - namespace += child.spelling + '::' - child = next(children) - while child.kind == CursorKind.TYPE_REF: - namespace = child.spelling.split()[-1] + '::' - child = next(children) - except StopIteration: - pass - - try: - child = next(children) - raise Exception("Unexpected %s child node in declaration" % child.type) - except StopIteration: - pass - - var = context[namespace + node.spelling] - if isinstance(var, EnumValue): - return var - else: - return VariableReference(context[namespace + node.spelling], node) - - def handle_member_ref_expr(self, node, context): - try: - children = node.get_children() - first_child = next(children) - ref = AttributeReference(self.handle(first_child, context), node.spelling) - except StopIteration: - # An implicit reference to `this` - ref = AttributeReference(SelfReference(), node.spelling) - try: - next(children) - raise Exception("Member reference expression has > 1 children.") - except StopIteration: - pass - - return ref - - def handle_call_expr(self, node, context): - try: - namespace = "" - children = node.get_children() - child = next(children) - - while child.kind == CursorKind.NAMESPACE_REF: - namespace += child.spelling + '::' - child = next(children) - prev_child = child - while child.kind == CursorKind.TYPE_REF: - child = next(children) - if prev_child.type.kind == TypeKind.RECORD: - # Class typerefs in a call include their own - # namespace definition. - namespace = prev_child.spelling.split()[-1] + '::' - else: - namespace += prev_child.spelling + '::' - prev_child = child - - first_child = self.handle(child, context) - if ((isinstance(first_child, VariableReference) - and first_child.node.type.kind == TypeKind.FUNCTIONPROTO) - or isinstance(first_child, AttributeReference)): - fn = Invoke(first_child) - - for child in children: - arg = self.handle(child, context) - if arg: - fn.add_argument(arg.clean_argument()) - - return fn - else: - # Implicit cast, functional cast, or - # constructor with no args - return first_child - except StopIteration: - return Invoke(TypeReference(context[namespace + node.spelling])) - - # def handle_block_expr(self, node, context): - - def handle_integer_literal(self, node, context): - # In order to preserve source formatting, we need to do some - # special handling. The literal from the AST will be processed - # into a decimal integer, losing all formatting. However, - # the token will be unreliable as a way of getting the token. - # So - get both; if they're numerically equal, use the token - # because it will have preserved formatting. If they aren't - # equal, the token is probably wrong; use the literal. - try: - literal_value = node.literal - token_value = next(node.get_tokens()).spelling - - try: - if int(token_value) == int(literal_value): - value = token_value - else: - raise ValueError() - except ValueError: - try: - if int(token_value, 16) == int(literal_value): - value = token_value - else: - try: - # Try octals - if int(token_value, 8) == int(literal_value): - value = token_value - else: - raise ValueError() - except ValueError: - raise ValueError() - except ValueError: - value = literal_value - except StopIteration: - # No tokens - value = literal_value - - return Literal(value) - - def handle_floating_literal(self, node, context): - try: - literal_value = node.literal - token_value = next(node.get_tokens()).spelling - if float(token_value) == float(literal_value): - value = token_value - else: - value = literal_value - except (StopIteration, ValueError): - # No tokens - value = literal_value - - return Literal(value) - - # def handle_imaginary_literal(self, node, context): - - def handle_string_literal(self, node, context): - return Literal(node.literal) - - def handle_character_literal(self, node, context): - return Literal(node.literal) - - def handle_paren_expr(self, node, context): - try: - children = node.get_children() - parens = Parentheses(self.handle(next(children), context)) - except StopIteration: - raise Exception("Parentheses must contain an expression.") - - try: - next(children) - raise Exception("Parentheses can only contain one expression.") - except StopIteration: - pass - - return parens - - def handle_unary_operator(self, node, context): - try: - children = node.get_children() - child = next(children) - - op = node.unary_operator - - # Dereferencing operator is a pass through. - # All others must be processed as defined. - if op == False: # TODO: Replace false with DEREF - unaryop = self.handle(child, context) - else: - value = self.handle(child, context) - unaryop = UnaryOperation(node.operator, value) - - except StopIteration: - raise Exception("Unary expression requires 1 child node.") - - try: - next(children) - raise Exception("Unary expression has > 1 child node.") - except StopIteration: - pass - - return unaryop - - def handle_array_subscript_expr(self, node, context): - try: - children = node.get_children() - - subject = self.handle(next(children), context) - index = self.handle(next(children), context) - value = ArraySubscript(subject, index) - except StopIteration: - raise Exception("Array subscript requires 2 child nodes.") - - try: - next(children) - raise Exception("Array subscript has > 2 child nodes.") - except StopIteration: - pass - - return value - - def handle_binary_operator(self, node, context): - try: - children = node.get_children() - lnode = next(children) - lvalue = self.handle(lnode, context) - - op = node.operator - - rnode = next(children) - rvalue = self.handle(rnode, context) - - binop = BinaryOperation(lvalue, op, rvalue) - except StopIteration: - raise Exception("Binary operator requires 2 child nodes.") - - try: - next(children) - raise Exception("Binary operator has > 2 child nodes.") - except StopIteration: - pass - - return binop - - def handle_compound_assignment_operator(self, node, context): - try: - children = node.get_children() - - lnode = next(children) - lvalue = self.handle(lnode, context) - - op = node.operator - - rnode = next(children) - rvalue = self.handle(rnode, context) - - binop = BinaryOperation(lvalue, op, rvalue) - except StopIteration: - raise Exception("Binary operator requires 2 child nodes.") - - try: - next(children) - raise Exception("Binary operator has > 2 child nodes.") - except StopIteration: - pass - - return binop - - def handle_conditional_operator(self, node, context): - try: - children = node.get_children() - - condition = self.handle(next(children), context) - true_value = self.handle(next(children), context) - false_value = self.handle(next(children), context) - - condop = ConditionalOperation(condition, true_value, false_value) - except StopIteration: - raise Exception("Conditional operator requires 3 child nodes.") - - try: - next(children) - raise Exception("Conditional operator has > 3 child nodes.") - except StopIteration: - pass - - return condop - - def handle_cstyle_cast_expr(self, node, context): - try: - children = node.get_children() - child = next(children) - - # Consume any namespace or type nodes; they won't be - # used for casting. - while child.kind in (CursorKind.NAMESPACE_REF, CursorKind.TYPE_REF): - child = next(children) - - cast = Cast(node.type.kind, self.handle(child, context)) - except StopIteration: - raise Exception("Cast expression requires 1 child node.") - - try: - next(children) - raise Exception("Cast expression has > 1 child node.") - except StopIteration: - pass - - return cast - - def handle_init_list_expr(self, node, context): - children = node.get_children() - - value = ListLiteral() - for child in children: - value.append(self.handle(child, context)) - - return value - - # def handle_addr_label_expr(self, node, context): - # def handle_stmtexpr(self, node, context): - # def handle_generic_selection_expr(self, node, context): - - def handle_cxx_null_ptr_literal_expr(self, node, context): - return Literal(None) - - def handle_gnu_null_expr(self, node, context): - return Literal(None) - - def handle_cxx_static_cast_expr(self, node, context): - try: - children = node.get_children() - child = next(children) - - # Consume any namespace or type nodes; they won't be - # used for casting. - while child.kind in (CursorKind.NAMESPACE_REF, CursorKind.TYPE_REF): - child = next(children) - - cast = Cast(node.type.kind, self.handle(child, context)) - except StopIteration: - raise Exception("Static cast expression requires 1 child node.") - - try: - next(children) - raise Exception("Static cast expression has > 1 child node.") - except StopIteration: - pass - - return cast - - def handle_cxx_dynamic_cast_expr(self, node, context): - try: - children = node.get_children() - child = next(children) - - # Consume any namespace or type nodes; they won't be - # used for casting. - while child.kind in (CursorKind.NAMESPACE_REF, CursorKind.TYPE_REF): - child = next(children) - - cast = Cast(node.type.kind, self.handle(child, context)) - except StopIteration: - raise Exception("Cast expression requires 1 child node.") - - try: - next(children) - raise Exception("Cast expression has > 1 child node.") - except StopIteration: - pass - - return cast - - def handle_cxx_reinterpret_cast_expr(self, node, context): - try: - children = node.get_children() - child = next(children) - - # Consume any namespace or type nodes; they won't be - # used for casting. - while child.kind in (CursorKind.NAMESPACE_REF, CursorKind.TYPE_REF): - child = next(children) - - cast = Cast(node.type.kind, self.handle(child, context)) - except StopIteration: - raise Exception("Cast expression requires 1 child node.") - - try: - next(children) - raise Exception("Cast expression has > 1 child node.") - except StopIteration: - pass - - return cast - - def handle_cxx_const_cast_expr(self, node, context): - try: - children = node.get_children() - child = next(children) - - # Consume any namespace or type nodes; they won't be - # used for casting. - while child.kind in (CursorKind.NAMESPACE_REF, CursorKind.TYPE_REF): - child = next(children) - - cast = Cast(node.type.kind, self.handle(child, context)) - except StopIteration: - raise Exception("Cast expression requires 1 child node.") - - try: - next(children) - raise Exception("Cast expression has > 1 child node.") - except StopIteration: - pass - - return cast - - def handle_cxx_functional_cast_expr(self, node, context): - try: - children = node.get_children() - - if node.type.kind in ( - TypeKind.CHAR_U, - TypeKind.UCHAR, - TypeKind.CHAR16, - TypeKind.CHAR32, - TypeKind.CHAR_S, - TypeKind.SCHAR, - TypeKind.WCHAR, - TypeKind.USHORT, - TypeKind.UINT, - TypeKind.ULONG, - TypeKind.ULONGLONG, - TypeKind.UINT128, - TypeKind.SHORT, - TypeKind.INT, - TypeKind.LONG, - TypeKind.LONGLONG, - TypeKind.INT128, - TypeKind.FLOAT, - TypeKind.DOUBLE, - TypeKind.LONGDOUBLE, - ): - cast = Cast(node.type.kind, self.handle(next(children), context)) - else: - cast = Invoke(self.handle(next(children), context)) - cast.add_argument(self.handle(next(children), context)) - except StopIteration: - raise Exception("Functional cast requires 2 child nodes.") - - try: - next(children) - raise Exception("Functional cast has > 2 child nodes.") - except StopIteration: - pass - - return cast - - # def handle_cxx_typeid_expr(self, node, context): - def handle_cxx_bool_literal_expr(self, node, context): - content = node.literal - return Literal('True' if content == 'true' else 'False') - - def handle_cxx_this_expr(self, node, context): - return SelfReference() - - # def handle_cxx_throw_expr(self, node, context): - def handle_cxx_new_expr(self, node, context): - children = node.get_children() - - # If the class being instantiated is in a namespace, the - # first children will be namespace nodes; these can be ignored. - child = next(children) - # print("FIRST CHILD", child.kind) - while child.kind == CursorKind.NAMESPACE_REF: - child = next(children) - # print("NS CHILD", child.kind) - - # The next nodes will be typedefs or a template reference describing - # the path to the class being instantiated. In most cases this will be - # a single node; however, in the case of nested classes, there will be - # multiple typedef nodes describing the access path. - while child.kind in (CursorKind.TYPE_REF, CursorKind.TEMPLATE_REF): - type_ref = child - child = next(children) - # print("TYPE CHILD", child.kind) - - # print("FINAL CHILD", child.kind) - new = New(self.handle(type_ref, context)) - - for arg in child.get_children(): - new.add_argument(self.handle(arg, context)) - - return new - - def handle_cxx_delete_expr(self, node, context): - # Delete has no meaning. - pass - # def handle_cxx_unary_expr(self, node, context): - # def handle_pack_expansion_expr(self, node, context): - # def handle_size_of_pack_expr(self, node, context): - # def handle_lambda_expr(self, node, context): - # def handle_unexposed_stmt(self, node, context): - # def handle_label_stmt(self, node, context): - - def handle_compound_stmt(self, node, context): - if context.statements is None: - context.statements = [] - for child in node.get_children(): - statement = self.handle(child, context) - if statement: - context.add_statement(statement) - - def handle_if_stmt(self, node, context): - children = node.get_children() - condition = self.handle(next(children), context) - if_statement = If(condition, context) - - true_term = self.handle(next(children), if_statement.if_true) - if true_term: - if_statement.if_true.add_statement(true_term) - - try: - # There are three possibilities here: - # 1) No false condition (i.e., an if with no else). This - # is caught by the exception handler because there - # will be no child node. - # 2) A bucket 'else' clause. The context passed to the - # handler will have the statements added to it. - # The handler will return None; the block passed - # as context is used as the if_false clause on the If. - # 3) No false condition (i.e., an if with no else). The - # handler will process this as a "sub-if", and return - # the sub-if clause. This clause is used as the - # if_false clause on the If. - if_false = Block(if_statement) - false_term = self.handle(next(children), if_false) - if false_term: - if_statement.if_false = false_term - else: - if_statement.if_false = if_false - except StopIteration: - pass - - try: - next(children) - raise Exception("Unexpected content in if statement") - except StopIteration: - pass - - return if_statement - - # def handle_switch_stmt(self, node, context): - # def handle_case_stmt(self, node, context): - # def handle_default_stmt(self, node, context): - - def handle_while_stmt(self, node, context): - - children = node.get_children() - - - condition = self.handle(next(children), context) - while_statement = While(condition, context) - self.handle(next(children), while_statement.statements) - - try: - next(children) - raise Exception("Unexpected content in while statement") - except StopIteration: - pass - - return while_statement - - def handle_do_stmt(self, node, context): - - children = node.get_children() - - do_statement = Do(context) - self.handle(next(children), do_statement.statements) - do_statement.condition = self.handle(next(children), do_statement.statements) - - try: - next(children) - raise Exception("Unexpected content in do statement") - except StopIteration: - pass - - return do_statement - - def handle_for_stmt(self, node, context): - - children = node.get_children() - child = next(children) - - init_stmt = None - expr_stmt = None - end_stmt = None - - # initial statement - if child.kind == CursorKind.DECL_STMT: - init_stmt = self.handle(child, context) - child = next(children) - - if child.kind == CursorKind.BINARY_OPERATOR: - expr_stmt = self.handle(child, context) - child = next(children) - - if child.kind == CursorKind.UNARY_OPERATOR: - end_stmt = self.handle(child, context) - child = next(children) - - for_statement = For(init_stmt, expr_stmt, end_stmt, context) - - # content - self.handle(child, for_statement.statements) - - try: - next(children) - raise Exception("Unexpected content in for statement") - except StopIteration: - pass - - return for_statement - - - # decl - # end - # increment - # content - - # def handle_goto_stmt(self, node, context): - # def handle_indirect_goto_stmt(self, node, context): - - def handle_continue_stmt(self, node, context): - # for loop cares if there's a continue - end_expr = None - parent = context - while parent and not (isinstance(parent, (For, While, Do))): - parent = parent.context - - if isinstance(parent, For): - end_expr = parent.end_expr - - - return Continue(end_expr) - - def handle_break_stmt(self, node, context): - return Break() - - def handle_return_stmt(self, node, context): - retval = Return() - try: - retval.value = self.handle(next(node.get_children()), context) - except StopIteration: - pass - - return retval - - # def handle_asm_stmt(self, node, context): - # def handle_cxx_catch_stmt(self, node, context): - # def handle_cxx_try_stmt(self, node, context): - # def handle_cxx_for_range_stmt(self, node, context): - # def handle_seh_try_stmt(self, node, context): - # def handle_seh_except_stmt(self, node, context): - # def handle_seh_finally_stmt(self, node, context): - # def handle_ms_asm_stmt(self, node, context): - - def handle_null_stmt(self, node, context): - pass - - def handle_decl_stmt(self, node, context): - try: - children = node.get_children() - statement = self.handle(next(children), context) - except StopIteration: - pass - - try: - self.handle(next(children), context) - raise Exception("Don't know how to handle multiple statements") - except StopIteration: - pass - - return statement - - def handle_translation_unit(self, node, tu): - for child in node.get_children(): - decl = self.handle(child, tu) - if decl: - decl.add_to_context(tu) - - # def handle_unexposed_attr(self, node, context): - # def handle_ib_action_attr(self, node, context): - # def handle_ib_outlet_attr(self, node, context): - # def handle_ib_outlet_collection_attr(self, node, context): - def handle_cxx_final_attr(self, node, context): - # No need to handle final declarations - pass - - def handle_cxx_override_attr(self, node, context): - # No need to handle override declarations - pass - - # def handle_annotate_attr(self, node, context): - # def handle_asm_label_attr(self, node, context): - # def handle_packed_attr(self, node, context): - # def handle_pure_attr(self, node, context): - # def handle_const_attr(self, node, context): - # def handle_noduplicate_attr(self, node, context): - # def handle_cudaconstant_attr(self, node, context): - # def handle_cudadevice_attr(self, node, context): - # def handle_cudaglobal_attr(self, node, context): - # def handle_cudahost_attr(self, node, context): - # def handle_cudashared_attr(self, node, context): - # def handle_visibility_attr(self, node, context): - # def handle_dllexport_attr(self, node, context): - # def handle_dllimport_attr(self, node, context): - # def handle_preprocessing_directive(self, node, context): - - def handle_macro_definition(self, node, context): - pass - - def handle_macro_instantiation(self, node, context): - # self.instantiated_macros[ - # (node.location.file.name, node.location.line, node.location.column) - # ] = self.macros.get(node.spelling, '') - pass - - def handle_inclusion_directive(self, node, context): - # Ignore inclusion directives - pass - - # def handle_module_import_decl(self, node, context): - # def handle_type_alias_template_decl(self, node, context): - - ############################################################ - # Objective-C methods - # If an algorithm exists in Objective C, implementing these - # methods will allow conversion of that code. - ############################################################ - # def handle_objc_synthesize_decl(self, node, context): - # def handle_objc_dynamic_decl(self, node, context): - # def handle_objc_super_class_ref(self, node, context): - # def handle_objc_protocol_ref(self, node, context): - # def handle_objc_class_ref(self, node, context): - # def handle_objc_message_expr(self, node, context): - # def handle_objc_string_literal(self, node, context): - # def handle_objc_encode_expr(self, node, context): - # def handle_objc_selector_expr(self, node, context): - # def handle_objc_protocol_expr(self, node, context): - # def handle_objc_bridge_cast_expr(self, node, context): - # def handle_obj_bool_literal_expr(self, node, context): - # def handle_obj_self_expr(self, node, context): - # def handle_objc_at_try_stmt(self, node, context): - # def handle_objc_at_catch_stmt(self, node, context): - # def handle_objc_at_finally_stmt(self, node, context): - # def handle_objc_at_throw_stmt(self, node, context): - # def handle_objc_at_synchronized_stmt(self, node, context): - # def handle_objc_autorelease_pool_stmt(self, node, context): - # def handle_objc_for_collection_stmt(self, node, context): - # def handle_objc_interface_decl(self, node, context): - # def handle_objc_category_decl(self, node, context): - # def handle_objc_protocol_decl(self, node, context): - # def handle_objc_property_decl(self, node, context): - # def handle_objc_ivar_decl(self, node, context): - # def handle_objc_instance_method_decl(self, node, context): - # def handle_objc_class_method_decl(self, node, context): - # def handle_objc_implementation_decl(self, node, context): - # def handle_objc_category_impl_decl(self, node, context): - - -# A simpler version of Parser that just -# dumps the tree structure. -class CodeDumper(BaseParser): - def __init__(self, verbosity): - super(CodeDumper, self).__init__() - self.verbosity = verbosity - self.filenames = set() - self.ignored_files = set() - - def parse(self, filenames, flags): - abs_filenames = [os.path.abspath(f) for f in filenames] - self.filenames.update(abs_filenames) - source_filenames = [f for f in abs_filenames if os.path.splitext(f)[1] != '.h'] - - self.tu = self.index.parse( - None, - args=source_filenames + flags, - options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD - ) - self.diagnostics(sys.stderr) - - self.handle(self.tu.cursor, 0) - - def handle(self, node, depth=0): - if (node.location.file is None - or os.path.abspath(node.location.file.name) in self.filenames): - - debug = [ - ' ' * depth, - node.kind, - '(type:%s | result type:%s)' % (node.type.kind, node.result_type.kind), - node.spelling, - node.location.file, - ] - if self.verbosity > 0: - debug.append([t.spelling for t in node.get_tokens()]) - print(*debug) - - for child in node.get_children(): - self.handle(child, depth + 1) - else: - if node.location.file.name.startswith('/usr/include'): - min_level = 2 - elif node.location.file.name.startswith('/usr/local'): - min_level = 2 - else: - min_level = 1 - - if node.location.file.name not in self.ignored_files: - if self.verbosity >= min_level: - print("Ignoring node in file %s" % node.location.file) - self.ignored_files.add(node.location.file.name) - - -if __name__ == '__main__': - opts = argparse.ArgumentParser( - description='Display AST structure for C++ file.', - ) - - opts.add_argument( - '-I', '--include', - dest='includes', - metavar='/path/to/includes', - help='A directory of includes', - action='append', - default=[] - ) - - opts.add_argument( - '-D', - dest='defines', - metavar='SYMBOL', - help='Preprocessor tokens to use', - action='append', - default=[] - ) - - opts.add_argument( - '-std', - help='The C/C++ standard to use (default: c++0x)', - default='c++0x' - ) - - opts.add_argument( - '-stdlib', - help='The standard library to use (default: libstdc++)', - default='libstdc++' - ) - - opts.add_argument( - '-v', '--verbosity', - action='count', - default=0 - ) - - opts.add_argument( - 'filename', - metavar='file.cpp', - help='The file(s) to dump.', - nargs="+" - ) - - args = opts.parse_args() - - dumper = CodeDumper(verbosity=args.verbosity) - dumper.parse( - args.filename, - flags=[ - '-I%s' % inc for inc in args.includes - ] + [ - '-D%s' % define for define in args.defines - ] + [ - '-std=%s' % args.std - ] + [ - '-stdlib=%s' % args.stdlib - ] - - ) \ No newline at end of file diff --git a/robloxpyc/plugin.py b/robloxpyc/plugin.py deleted file mode 100644 index fb0efe0..0000000 --- a/robloxpyc/plugin.py +++ /dev/null @@ -1,43 +0,0 @@ -import pyflakes.api as api -import requests -from flask import Flask, request -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from reporter import Reporter - import pytranslator -else: - from .reporter import Reporter - from . import pytranslator - -def p(): - app = Flask(__name__) - print("The plugin is decreapted. Please use the CLI alongside a Studio+VSCode sync plugin.") - @app.route('/', methods=["GET", "POST"]) - def base_page(): - code = (request.data).decode() - try: - translator = pytranslator.Translator() - lua_code = translator.translate(code) - except Exception as e: - return "CompileError!:"+str(e) - - return lua_code - - @app.route('/err', methods=["GET", "POST"]) - def debug(): - code = (request.data).decode() - rep = Reporter() - num = str(api.check(code, "roblox.py", rep)) - print(num) - return rep.diagnostics - - @app.route("/lib", methods=["GET"]) - def library(): - translator = pytranslator.Translator() - return translator.get_luainit([]) - - app.run( - host='0.0.0.0', - port=5555 - ) \ No newline at end of file diff --git a/robloxpyc/pytranslator.py b/robloxpyc/pytranslator.py deleted file mode 100644 index af28e24..0000000 --- a/robloxpyc/pytranslator.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Python to lua translator class""" -import ast -import os -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from config import Config - from nodevisitor import NodeVisitor - from header import header, pyfooter - from luainit import initcode, allfunctions, generatewithlibraries, robloxfunctions -else: - from .config import Config - from .nodevisitor import NodeVisitor - - from .header import header, pyfooter - from .luainit import initcode, allfunctions, generatewithlibraries, robloxfunctions - -class Translator: - """Python to lua main class translator""" - def __init__(self, config=None, show_ast=False): - self.config = config if config is not None else Config() - self.show_ast = show_ast - - self.output = [] - - def translate(self, pycode): - """Translate python code to lua code""" - py_ast_tree = ast.parse(pycode) - - visitor = NodeVisitor(config=self.config) - - if self.show_ast: # - print(ast.dump(py_ast_tree)) - - visitor.visit(py_ast_tree) - - self.output = visitor.output - # check every single line for function calls - functions = [] - for i in range(len(self.to_code().split("\n"))): - # check if a function is being called, like print() - - for function in (allfunctions+robloxfunctions): - if function in self.to_code().split("\n")[i] and function not in functions: - functions.append(function) - - - # create header for function calls - newheader = header(functions) - - return newheader+self.to_code()+pyfooter - - def to_code(self, code=None, indent=0): - """Create a lua code from the compiler output""" - code = code if code is not None else self.output - - def add_indentation(line): - """Add indentation to the given line""" - indentation_width = 4 - indentation_space = " " - - indent_copy = max(indent, 0) - - return indentation_space * indentation_width * indent_copy + line - - lines = [] - for line in code: - if isinstance(line, str): - lines.append(add_indentation(line)) - elif isinstance(line, list): - sub_code = self.to_code(line, indent + 1) - lines.append(sub_code) - - return "\n".join(lines) - - @staticmethod - def get_luainit(items): - return generatewithlibraries(items) diff --git a/robloxpyc/reporter.py b/robloxpyc/reporter.py deleted file mode 100644 index 521198e..0000000 --- a/robloxpyc/reporter.py +++ /dev/null @@ -1,67 +0,0 @@ -import re - -class Reporter: - """ - Formats the results of pyflakes checks to users. - """ - def __init__(self): - self.diagnostics = [] - - def unexpectedError(self, filename, msg): - """ - An unexpected error occurred attemptinh to process C{filename}. - - @param filename: The path to a file that we could not process. - @ptype filename: C{unicode} - @param msg: A message explaining the problem. - @ptype msg: C{unicode} - """ - self.diagnostics.append(f"1{filename}: {msg}\n") - - def syntaxError(self, filename, msg, lineno, offset, text): - """ - There was a syntax error in C{filename}. - - @param filename: The path to the file with the syntax error. - @ptype filename: C{unicode} - @param msg: An explanation of the syntax error. - @ptype msg: C{unicode} - @param lineno: The line number where the syntax error occurred. - @ptype lineno: C{int} - @param offset: The column on which the syntax error occurred, or None. - @ptype offset: C{int} - @param text: The source code containing the syntax error. - @ptype text: C{unicode} - """ - if text is None: - line = None - else: - line = text.splitlines()[-1] - - # lineno might be None if the error was during tokenization - # lineno might be 0 if the error came from stdin - lineno = max(lineno or 0, 1) - - if offset is not None: - # some versions of python emit an offset of -1 for certain encoding errors - offset = max(offset, 1) - self.diagnostics.append('1%s:%d:%d: %s\n' % - (filename, lineno, offset, msg)) - else: - self.diagnostics.append('1%s:%d: %s\n' % (filename, lineno, msg)) - - if line is not None: - self.diagnostics.append(line) - self.diagnostics.append('\n') - if offset is not None: - self.diagnostics.append(re.sub(r'\S', ' ', line[:offset - 1]) + - "^\n") - - def flake(self, message): - """ - pyflakes found something wrong with the code. - - @param: A L{pyflakes.messages.Message}. - """ - self.diagnostics.append("2"+str(message)) - self.diagnostics.append('\n') diff --git a/robloxpyc/robloxpy.py b/robloxpyc/robloxpy.py deleted file mode 100644 index ea4dec7..0000000 --- a/robloxpyc/robloxpy.py +++ /dev/null @@ -1,517 +0,0 @@ -"""Handles the main interface""" - -# PYPI -from flask import Flask, request -from pyflakes import api -from packaging import version -from tqdm import tqdm -from time import sleep -import sys -import os -# written by luxkatana/TheTrojanHorse fix: -# fix importing problems using the CLI - -EXPECTED_PATH_NEEDED: str = os.path.dirname(__file__) -if len(set(filter(lambda path: EXPECTED_PATH_NEEDED == path, sys.path))) == 0: - sys.path.append(EXPECTED_PATH_NEEDED) - - -# FILES -if __name__ == "__main__": - from robloxpyc import colortext #ctranslator is old and not used - - # MODULAR - from errormanager import * - from installationmanager import * - from configmanager import * - from textcompiler import * - from basecompilers import * - from util import * - from plugin import * - from loader import loader - from climaker import newIncli, newIncli2, newLanguage - from wally import wallyget -else: - from . import colortext #ctranslator is old and not used - - # MODULAR - from .errormanager import * - from .installationmanager import * - from .configmanager import * - from .textcompiler import * - from .basecompilers import * - from .util import * - from .plugin import * - from .loader import loader - from .climaker import newIncli, newIncli2, newLanguage - from .wally import wallyget -# BUILTIN -import subprocess,shutil,sys,threading,json,requests,traceback,pkg_resources,re,sys,webbrowser,pickle, zipfile - - -registryrawurl = "https://raw.githubusercontent.com/roblox-pyc/registry/main/registry.json" -global count -count = 0 - -try: - registry = json.loads(requests.get(registryrawurl).text) -except json.JSONDecodeError: - print(colortext.white("Import will not work, registry is corrupted. Please report this issue to the github repo, discord server, or the devforum post\nthanks!")) - registry = {} - - -w = newLanguage(".py", pycompile, '"""%s"""') -cw = newLanguage(".c", ccompile, '/*%s*/') -cpw = newLanguage(".cpp", cppcompile, '/*%s*/') -lunar = newLanguage(".moon", lunarcompile, '--[[%s]]') - -globalincli = newIncli(["py", "c", "cpp", "moon"], allcompile) -globalincli2 = newIncli2(["py", "c", "cpp", "moon"], allcompile) - -def pyc(): - title = colortext.magenta("roblox-pyc", ["bold"]) - py = colortext.blue("roblox-py", ["bold"]) - c = colortext.blue("roblox-c", ["bold"]) - cpp = colortext.blue("roblox-cpp", ["bold"]) - lunar = colortext.blue("roblox-lunar", ["bold"]) - border = colortext.white("--------------------") - blank = colortext.blue("roblox-", ["bold"])+colortext.magenta("") - blank2 = colortext.blue("rblx-", ["bold"])+colortext.magenta("") - blankpath = colortext.magenta("") - selftool = colortext.blue("roblox-pyc", ["bold"]) - shortselftool = colortext.blue("rblx-pyc", ["bold"]) - shorterselftool = colortext.blue("rpyc", ["bold"]) - print(str(sys.argv)) - try: - if sys.argv[1] == "config": - # Open config menu - print(f""" -Config menu -{border} -1 - {py} -2 - {c} -3 - {cpp} -4 - {lunar} -5 - General - """) - returnval = input("Select which config to open: ") - - if returnval == "1": - print(f"{py} doesnt need to be configured!") - elif returnval == "2": - print(f""" -Configuring {c} -{border} -1 - Change std -2 - Change stdlib - """) - - inputval = input("Select which config to open: ") - if inputval == "1": - returned = input("Enter the std, it currently is %s: " % getconfig("c", "std", "c11")) - setconfig("c", "std", returned, "c11") - elif inputval == "2": - returned = input("Enter the stdlib, it currently is %s: " % getconfig("c", "stdlib", "libc")) - setconfig("c", "stdlib", returned, "libc") - elif returnval == "3": # - print(f""" -Configuring {cpp} -{border} -1 - Change std -2 - Change stdlib - """) - - inputval = input("Select which config to open: ") - if inputval == "1": - returned = input("Enter the std, it currently is %s: " % getconfig("cpp", "std", "c++11")) - setconfig("cpp", "std", returned, "c++11") - elif inputval == "2": - returned = input("Enter the stdlib, it currently is %s: " % getconfig("cpp", "stdlib", "libc++")) - setconfig("cpp", "stdlib", returned, "libc++") - elif returnval == "4": - print(f"{lunar} doesnt need to be configured!") - elif returnval == "5": - print(f""" -Configuring General Settings -{border} -1 - Change C and C++ dylib -2 - Enable or diable autocompile - """) - inputval = input("Select which config to open: ") - if inputval == "1": - returned = input("Enter the dynamic library file, it currently is %s: " % getconfig("c", "dynamiclibpath", "None")) - setconfig("c", "dynamiclibpath", returned, "None") - elif inputval == "2": - returned = input("Would you like to turn autocompile (on/off)") - if returned == "on": - setconfig("general", "autocompile", True, False) - elif returned == "off": - setconfig("general", "autocompile", False, False) - else: - print(error("not a valid option!")) - elif returnval == "6": - colortext.nil(colortext.rainbow_text("Welcome to the secret menu!")) - print("This contains many developer options and some goofy ones too!") - print(f""" - 1 - Traceback on error (Reccomended off, for roblox-pyc developers) - 2 - TTS on error (macOS only) - """) - print(f"Select which", end=" ") - colortext.rainbow_text("secret", end=" ") - inputval = input("config to open: ") - if inputval == "1": - returned = input("Click enter to confirm, CTRL+C to cancel: ") - setconfig("general", "traceback", returned, None) - elif inputval == "2": - if not sys.platform == "darwin": - print(error("I ALREADY TOLD YOU, THIS IS MACOS ONLY!")) - return - setconfig("general", "goofy", returned, None) - elif inputval == "3": - colortext.nil(colortext.rainbow_text("Welcome to the secret secret menu, sadly this is empty for now! :(")) - else: - print(error("Aw man, you didnt select a valid option!")) - else: - print(error("Invalid option!")) - elif sys.argv[1] == "devforum": - webbrowser.open("https://devforum.com") - elif sys.argv[1] == "discord": - webbrowser.open("https://discord.gg/RAXYEjj3") - elif sys.argv[1] == "github": - webbrowser.open("https://github.com/AsynchronousAI/roblox-pyc") - elif sys.argv[1] == "help": - raise IndexError - elif sys.argv[1] == "w": - print(colortext.magenta("Ready to compile ", os.path.join(os.path.dirname(os.path.realpath(__file__)))+" ...\n Type 'exit' to exit, Press enter to compile.")) - globalincli() - elif sys.argv[1] == "d" or sys.argv[1] == ".": - print(colortext.magenta("Ready to compile ", os.path.join(os.path.dirname(os.path.realpath(__file__)))+" ...\n Type 'exit' to exit, Press enter to compile.")) - globalincli2() - elif sys.argv[1] == "format": - print(warn("Are you sure, this will reformat the compiled directory and delete uncompatible files, this is for when a bug occured.", "roblox-pyc")) - if input("Type 'yes' to continue: ") == "yes": - # Delete all files that arent .py, .moon, .lua, .c, .cpp - filtercompiledfolder() - print(colortext.green("Deleted all uncompatible files!")) - elif sys.argv[1] == "p": - print(error("Plugins are only supported for python!", "roblox-pyc")) - elif sys.argv[1] == "lib": - # sys.argv[2] is the path to the file, create a new file there with the name robloxpyc.lua, and write the library to it - lib() - elif sys.argv[1] == "c": - decreapted("c") - print(error("Cannot replace all files for a general language, please specify a language by using rbxpy, rbxlun, rbxc, rbxcpp", "roblox-pyc")) - elif sys.argv[1] == "cd": - print(error("Cannot replace all files for a general language, please specify a language by using rbxpy, rbxlun, rbxc, rbxcpp", "roblox-pyc")) - elif sys.argv[1] == "tsc": - # Pretty much c but for typescript and works - if not check_roblox_ts(): - if not check_npms(): - install_npms() - install_roblox_ts() - confirm = input(warn("Are you sure? This will delete all .lua files and add a .ts file with the same name.\n\nType 'yes' to continue.")) - if confirm == "yes": - path = os.getcwd()+"/src" - - for r, d, f in os.walk(path): - for file in f: - if '.lua' in file: - luafilecontents = "" - with open(os.path.join(r, file), "r") as f: - luafilecontents = f.read() - - os.remove(os.path.join(r, file)) - - # create new file with same name but .py and write the lua file contents to it - open(os.path.join(r, file.replace(".lua", ".ts")), "x").close() - # write the old file contents as a C++ comment - open(os.path.join(r, file.replace(".lua", ".ts")), "w").write("/*\n"+luafilecontents+"\n*/") - - print(colortext.green("Converted to typescript "+os.path.join(r, file)+" as "+file.replace(".lua", ".moon"))) - elif sys.argv[1] == "info": - subprocess.call(["pip", "show", "roblox-pyc"]) - check_for_updates() - elif sys.argv[1] == "install": - # Check registry for package - if sys.argv[2] in registry: - # Find out how to install, cli or package - item = registry[sys.argv[2]] - type = item["type"] - - if type == "cli": - if True: - print(error("CLI packages are not supported on this build!", "roblox-pyc")) - return - # git clone the files to this scripts path - print(colortext.green("Installing "+sys.argv[2]+" ...")) - selfpath = os.path.dirname(os.path.realpath(__file__)) - # create new dir in selfpath called sys.argv[2] - os.mkdir(os.path.join(selfpath, sys.argv[2])) - - subprocess.call(["git", "clone", item["url"], os.path.join(selfpath, sys.argv[2])]) - - # add to config - newlist = getconfig("general", "cli", []) - newlist.append({"name": sys.argv[2], "path": os.path.join(selfpath, sys.argv[2]), "mainscript": item["mainscript"], "target": item["target"], "command": item["command"]}) - elif type == "luaext": - # save to config the name and url data after request - print(colortext.green("Fetching "+sys.argv[2]+" ...")) - newlist = getconfig("general", "luaext", []) - packagedata = json.loads(requests.get(item["url"]).text) - fileurl = packagedata["file"] - - newlist.append({"name": sys.argv[2], "data": requests.get(fileurl).text, "var": packagedata["outputvar"]}) - setconfig("general", "luaext", newlist, []) - print(colortext.green("Fetched "+sys.argv[2]+"!")) - elif type == "package": - # Create new folder in cwd called dependencies if it doesnt exist - print(colortext.green("Installing "+sys.argv[2]+" ...")) - exists = os.path.exists(os.path.join(os.getcwd(), "dependencies")) - if not exists: - lib() - - # Gitclone item["url"] to dependencies folder - subprocess.call(["git", "clone", item["url"], os.path.join(os.getcwd(), "dependencies", sys.argv[2])]) - print(colortext.green("Installed "+sys.argv[2]+"!")) - elif sys.argv[2].startswith("@") and not sys.argv[2].startswith("@rbxts"): - author = sys.argv[2].split("/")[0].replace("@", "") - name = sys.argv[2].split("/")[1] - wallyget(author, name) - elif sys.argv[2].startswith("@rbxts"): - # Use NPM - print(warn("Fetching from NPM is still not stable, you might get missing files or files in the wrong place.")) - if not check_npms(): - install_npms() - # Install to /dependencies not /node_modules - subprocess.call(["npm", "install", sys.argv[2], "--prefix=dependencies"]) - # Delete dependencies/package-lock.json and dependencies/package.json. Use try except - try: - os.remove(os.path.join(os.getcwd(), "dependencies", "package-lock.json")) - except: - pass - try: - os.remove(os.path.join(os.getcwd(), "dependencies", "package.json")) - except: - pass - try: - os.remove(os.path.join(os.getcwd(), "dependencies", ".package.json")) - except: - pass - try: - os.remove(os.path.join(os.getcwd(), "dependencies", ".package-lock.json")) - except: - pass - - # Unpack dependencies/node_modules to dependencies - for r, d, f in os.walk(os.path.join(os.getcwd(), "dependencies", "node_modules")): - for file in f: - shutil.move(os.path.join(r, file), os.path.join(os.getcwd(), "dependencies")) - # Delete dependencies/node_modules - shutil.rmtree(os.path.join(os.getcwd(), "dependencies", "node_modules")) - # If a dependency/.package.json exists or a dependency/.package-lock.json exists, delete it - try: - os.remove(os.path.join(os.getcwd(), "dependencies", ".package.json")) - except: - pass - try: - os.remove(os.path.join(os.getcwd(), "dependencies", ".package-lock.json")) - except: - pass - try: - os.remove(os.path.join(os.getcwd(), "dependencies", "package-lock.json")) - except: - pass - try: - os.remove(os.path.join(os.getcwd(), "dependencies", "package.json")) - except: - pass - - - else: - print(warn("roblox-pyc: Package not in registry!")+"\n\n"+info("If you are trying to install from Wally enter the package name as @/")+"\n\n"+info("If you are trying to install from roblox-ts enter the package name as @rbxts/")+"\nInstall from one of these other package managers:") - print(""" - 1 - luarocks - 2 - pip (compiles to lua) - 3 - pip3 (compiles to lua) - 5 - None - """) - returnval = input("Select which package manager to use: ") - if returnval == "1": - # install to dependencies folder - if not check_luarocks(): - install_luarocks() - subprocess.call(["luarocks", "install", sys.argv[2], "--tree=dependencies"]) - elif returnval == "2": - # install to dependencies folder - subprocess.call(["pip", "install", sys.argv[2], "--target=dependencies", "--upgrade"]) - # compile the newly added directory to lua - elif returnval == "3": - # install to dependencies folder - subprocess.call(["pip3", "install", sys.argv[2], "--target=dependencies", "--upgrade"]) - # compile the newly added directory to lua - else: - print("Invalid option or exited.") - return - print("Compiling to luau...") - #global count - #count = 0 - endcount = 0 - for r, d, f in os.walk(os.path.join(os.getcwd(), "dependencies")): - for file in f: - if file.endswith(".py") or file.endswith(".moon"): - endcount+=1 - newloader = loader(endcount) - for r, d, f in os.walk(os.path.join(os.getcwd(), "dependencies")): - # if dir name is __pycache__ delete it - if os.path.basename(r) == "__pycache__": - # clear children - for child in os.listdir(r): - try: - os.remove(os.path.join(r, child)) - except: - pass - try: - os.rmdir(r) - except: - pass - - for file in f: - if file.endswith(".py"): - endcount+=1 - threading.Thread(target=pycompile, args=(r, file, newloader)).start() - - # delete old file - os.remove(os.path.join(r, file)) - elif file.endswith(".moon"): - endcount+=1 - threading.Thread(target=lunarcompile, args=(r, file, newloader)).start() - - # delete old file - os.remove(os.path.join(r, file)) - elif file.endswith(".c") or file.endswith(".cpp"): - candcpperror() - else: - othercompile(r, file) - - - - newloader.yielduntil() - print("Successfully installed "+sys.argv[2]+"!") - print(warn("Since these modules are from 3rd party sources, they may not work in the roblox environment and you may encounter errors, this is feauture is experimental and any issues in your code caused by this is not our fault.")) - - elif sys.argv[1] == "uninstall": - # Find out how to install, cli or package - item = registry[sys.argv[2]] - type = item["type"] - - # for cli do nothing, for luaext remove from config, for package remove from dependencies folder - if type == "cli": - pass - elif type == "luaext": - currentlist = getconfig("general", "luaext", []) - # remove, if not found error - found = False - - for i in currentlist: - if i["name"] == sys.argv[2]: - currentlist.remove(i) - found = True - if not found: - print(error("Module not found!", "roblox-pyc")) - else: - setconfig("general", "luaext", currentlist, []) - print(colortext.green("Uninstalled "+sys.argv[2]+"!")) - elif type == "package": - dependenciesPath = os.path.join(os.getcwd(), "dependencies") - # if it doesnt exist error - if not os.path.exists(dependenciesPath): - print(error("Dependencies folder not found! Creating one now...", "roblox-py")) - lib() - return - # remove, if not found error - if not os.path.exists(os.path.join(dependenciesPath, sys.argv[2])): - print(error("Package not found!", "roblox-py")) - - if os.path.exists(os.path.join(dependenciesPath, sys.argv[2])): - shutil.rmtree(os.path.join(dependenciesPath, sys.argv[2])) - print(colortext.green("roblox-pyc: Uninstalled "+sys.argv[2]+"!")) - elif sys.argv[1] == "list": - # First list all items in config - print(colortext.green("Extensions:")) - for i in getconfig("general", "luaext", []): - print((" - "+i["name"])) - - print(colortext.green("Packages:")) - # Then list all items in dependencies folder - dependenciesPath = os.path.join(os.getcwd(), "dependencies") - if not os.path.exists(dependenciesPath): - print(warn("roblox-pyc: Dependencies folder not found! Creating one now...")) - lib() - return - for i in os.listdir(dependenciesPath): - print((" - "+i)) - else: - raise IndexError - except IndexError: - print(f""" -{title} -{border} - CLIs: - - {py} - Python to Lua | Best for a functional and simple language - - {c} - C to Lua | Best for learning a more complicated language for fun and educational purposes - - {cpp} - C++ to Lua | Best for learning a more complicated OOP language for fun and educational purposes - - {lunar} - Lunar to Lua | Best for learning a language with some great syntax sugar - {border} - NOTES: - - {py} is the only one that supports plugins, and it supports full python 3.13, which is a dev build of python - - {c} and {cpp} are only capable of light conversions, and are not capable of converting complex code at the time of writing. - - {lunar} is based off MoonScript, and is completed and reccomended if you want a really nice language with good syntax sugar. - - I would highly reccomend {py} and {lunar} for production use over ideal lua, as they are much more powerful and easier to use. - - At the moment lunar is the exact same as moonscript, but adding roblox specific features is planned. - - rpyc and rblx-pyc can be used rather than roblox-pyc, they are just shorter versions of the name. - {border} - CLI DOCS: - - {blank} w - Click enter in the terminal to compile all scripts - - {blank} p - Start the plugin server (only for {py}) - - {blank} lib - Generate dependencies folder with stdlib - - {blank} c - Convert all .lua files to targeted language files, it will comment the existing lua code - - {blank2} w - Click enter in the terminal to compile all scripts - - {blank2} p - Start the plugin server (only for {py}) - - {blank2} lib - Generate dependencies folder with stdlib - - {blank2} c - Convert all .lua files to targeted language files, it will comment the existing lua code - - {selftool} config - Open the config menu - - {selftool} devforum - Open the devforum page in a browser - - {selftool} discord - Open the discord server in a browser - - {selftool} github - Open the github page in a browser - - {selftool} install - Install a item from the registry. Read docs for more info - - {selftool} uninstall - Uninstall a item from the registry. Read docs for more info - - {selftool} list - List all installed packages - {border} - MORE HELP: - - Devforum - - Discord - - Github Issues - - """) - except KeyboardInterrupt: - print(colortext.red("Aborted!")) - sys.exit(0) - - -if __name__ == "__main__": - print(colortext.blue("Test mode")) - mode = input("Select which module to run (1, 2, 3, 4, 5): ") - if os.environ.get("ENABLE_BETA_RPYC"): - print(colortext.magenta("important")+" the following code will be run in beta mode, robloxts support, C(++) support, etc. will all be enabled.") - - if mode == "1": - w() - elif mode == "2": - cw() - elif mode == "3": - cpw() - elif mode == "4": - lunar() - else: - pyc() - diff --git a/robloxpyc/sealang.cpp b/robloxpyc/sealang.cpp deleted file mode 100644 index fb86696..0000000 --- a/robloxpyc/sealang.cpp +++ /dev/null @@ -1,236 +0,0 @@ -#include "sealang.h" - -#include "clang/AST/Stmt.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" -#include "llvm/ADT/SmallString.h" - -/************************************************************************ - * Duplicated libclang functionality - * - * The following methods are duplicates of methods that are implemented - * in libclang, but aren't exposed as symbols that can be used by third- - * party libraries. - ************************************************************************/ - -namespace clang { - enum CXStringFlag { - /// CXString contains a 'const char *' that it doesn't own. - CXS_Unmanaged, - - /// CXString contains a 'const char *' that it allocated with malloc(). - CXS_Malloc, - - /// CXString contains a CXStringBuf that needs to be returned to the - /// CXStringPool. - CXS_StringBuf - }; - - const clang::Stmt *getCursorStmt(CXCursor cursor) { - if (cursor.kind == CXCursor_ObjCSuperClassRef || - cursor.kind == CXCursor_ObjCProtocolRef || - cursor.kind == CXCursor_ObjCClassRef) { - - return nullptr; - } - return static_cast(cursor.data[1]); - } - - const clang::Expr *getCursorExpr(CXCursor cursor) { - return clang::dyn_cast_or_null(getCursorStmt(cursor)); - } - - namespace cxstring { - CXString createEmpty() { - CXString str; - str.data = ""; - str.private_flags = CXS_Unmanaged; - return str; - } - - CXString createDup(StringRef string) { - CXString result; - char *spelling = static_cast(malloc(string.size() + 1)); - memmove(spelling, string.data(), string.size()); - spelling[string.size()] = 0; - result.data = spelling; - result.private_flags = (unsigned) CXS_Malloc; - return result; - } - - } -} - -/************************************************************************ - * New Sealang functionality - * - * The following methods expose useful features of the LLVM AST. They are - * all potentially candidates for inclusion upstream in libclang. - ************************************************************************/ - -CXString clang_Cursor_getOperatorString(CXCursor cursor) -{ - if (cursor.kind == CXCursor_BinaryOperator) { - clang::BinaryOperator *op = (clang::BinaryOperator *) clang::getCursorExpr(cursor); - return clang::cxstring::createDup(clang::BinaryOperator::getOpcodeStr(op->getOpcode())); - } - - if (cursor.kind == CXCursor_CompoundAssignOperator) { - clang::CompoundAssignOperator *op = (clang::CompoundAssignOperator*) clang::getCursorExpr(cursor); - return clang::cxstring::createDup(clang::BinaryOperator::getOpcodeStr(op->getOpcode())); - } - - if (cursor.kind == CXCursor_UnaryOperator) { - clang::UnaryOperator *op = (clang::UnaryOperator*) clang::getCursorExpr(cursor); - return clang::cxstring::createDup(clang::UnaryOperator::getOpcodeStr(op->getOpcode())); - } - - return clang::cxstring::createEmpty(); -} - -clang::BinaryOperatorKind clang_Cursor_getBinaryOpcode(CXCursor cursor) -{ - if (cursor.kind == CXCursor_BinaryOperator) { - clang::BinaryOperator *op = (clang::BinaryOperator *) clang::getCursorExpr(cursor); - return static_cast(op->getOpcode()); - } - - if (cursor.kind == CXCursor_CompoundAssignOperator) { - clang::CompoundAssignOperator *op = (clang::CompoundAssignOperator *) clang::getCursorExpr(cursor); - return static_cast(op->getOpcode()); - } - - return (clang::BinaryOperatorKind) 99999; -} - -clang::UnaryOperatorKind clang_Cursor_getUnaryOpcode(CXCursor cursor) -{ - if (cursor.kind == CXCursor_UnaryOperator) { - clang::UnaryOperator *op = (clang::UnaryOperator*) clang::getCursorExpr(cursor); - return static_cast(op->getOpcode()); - } - - return (clang::UnaryOperatorKind) 99999; -} - -CXString clang_Cursor_getLiteralString(CXCursor cursor) -{ - if (cursor.kind == CXCursor_IntegerLiteral) { - clang::IntegerLiteral *intLiteral = (clang::IntegerLiteral *) clang::getCursorExpr(cursor); - return clang::cxstring::createDup(intLiteral->getValue().toString(10, true)); - } - - if (cursor.kind == CXCursor_FloatingLiteral) { - clang::FloatingLiteral *floatLiteral = (clang::FloatingLiteral *) clang::getCursorExpr(cursor); - llvm::SmallString<1024> str; - floatLiteral->getValue().toString(str); - return clang::cxstring::createDup(str.c_str()); - } - - if (cursor.kind == CXCursor_CharacterLiteral) { - clang::CharacterLiteral *charLiteral = (clang::CharacterLiteral *) clang::getCursorExpr(cursor); - char c[2]; - c[0] = (char) charLiteral->getValue(); - c[1] = '\0'; - return clang::cxstring::createDup(c); - } - - if (cursor.kind == CXCursor_StringLiteral) { - clang::StringLiteral *stringLiteral = (clang::StringLiteral *) clang::getCursorExpr(cursor); - return clang::cxstring::createDup(stringLiteral->getBytes()); - } - - if (cursor.kind == CXCursor_CXXBoolLiteralExpr) { - clang::CXXBoolLiteralExpr *boolLiteral = (clang::CXXBoolLiteralExpr *) clang::getCursorExpr(cursor); - return clang::cxstring::createDup(boolLiteral->getValue() ? "true" : "false"); - } - - return clang::cxstring::createEmpty(); -} - -// CXCursor clang_getForStmtInit(CXCursor cursor) -// { -// if(cursor.kind!=CXCursor_ForStmt) return MakeCXCursorInvalid(CXCursor_InvalidCode); - -// ForStmt* Node=(ForStmt*)(cursor.data[1]); -// const CXTranslationUnit tu=(const CXTranslationUnit)(cursor.data[2]); - -// Stmt* init=Node->getInit(); -// if (init) return MakeCXCursor(init,0,tu); -// else return MakeCXCursorInvalid(CXCursor_NoDeclFound); -// } - -// CXCursor clang_getForStmtCond(CXCursor cursor) -// { -// if(cursor.kind!=CXCursor_ForStmt) return MakeCXCursorInvalid(CXCursor_InvalidCode); - -// ForStmt* Node=(ForStmt*)(cursor.data[1]); -// const CXTranslationUnit tu=(const CXTranslationUnit)(cursor.data[2]); - -// Stmt* cond=Node->getCond(); -// if (cond) return MakeCXCursor(cond,0,tu); -// else return MakeCXCursorInvalid(CXCursor_NoDeclFound); -// } - -// CXCursor clang_getForStmtInc(CXCursor cursor) -// { -// if(cursor.kind!=CXCursor_ForStmt) return MakeCXCursorInvalid(CXCursor_InvalidCode); - -// ForStmt* Node=(ForStmt*)(cursor.data[1]); -// const CXTranslationUnit tu=(const CXTranslationUnit)(cursor.data[2]); - -// Stmt* inc=Node->getInc(); -// if (inc) return MakeCXCursor(inc,0,tu); -// else return MakeCXCursorInvalid(CXCursor_NoDeclFound); -// } - -// CXCursor clang_getForStmtBody(CXCursor cursor) -// { -// if(cursor.kind!=CXCursor_ForStmt) return MakeCXCursorInvalid(CXCursor_InvalidCode); - -// ForStmt* Node=(ForStmt*)(cursor.data[1]); -// const CXTranslationUnit tu=(const CXTranslationUnit)(cursor.data[2]); - -// Stmt* body=Node->getBody(); -// if (body) return MakeCXCursor(body,0,tu); -// else return MakeCXCursorInvalid(CXCursor_NoDeclFound); -// } - -/************************************************************************ - * Python module definition - * - * This is a stub module definition; we aren't exposing any Python - * methods - we're just making the module .so easy to find. - ************************************************************************/ - -static PyMethodDef methods[] = { - {NULL, NULL, 0, NULL} -}; - -#if PY_MAJOR_VERSION <= 2 - -PyMODINIT_FUNC initsealang() -{ - (void) Py_InitModule("sealang", methods); -} - -#else - -static struct PyModuleDef sealangmodule = { - PyModuleDef_HEAD_INIT, - "sealang", - NULL, - -1, - methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC PyInit_sealang() -{ - return PyModule_Create(&sealangmodule); -} - -#endif \ No newline at end of file diff --git a/robloxpyc/sealang.h b/robloxpyc/sealang.h deleted file mode 100644 index c2df622..0000000 --- a/robloxpyc/sealang.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef SEALANG_H -#define SEALANG_H - -#include "Python.h" - -#include "clang/AST/OperationKinds.h" -#include "clang-c/Index.h" -#include "clang-c/CXString.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Returns string representation of unary and binary operators - */ -CXString clang_Cursor_getOperatorString(CXCursor cursor); - -/** - * \brief Returns Opcode of binary operator - */ -clang::BinaryOperatorKind clang_Cursor_getBinaryOpcode(CXCursor cursor); - -/** - * \brief Returns Opcode of unary operator - */ -clang::UnaryOperatorKind clang_Cursor_getUnaryOpcode(CXCursor cursor); - -/** - * \brief Returns string representation of literal cursor (1.f, 1000L, etc) - */ -CXString clang_Cursor_getLiteralString(CXCursor cursor); - -/** - * \brief Returns for-loop init cursor [for(init;cond;inc)], or CXCursor_NoDeclFound if there is no decl, - * or CXCursor_InvalidCode if C is not CXCursor_ForStmt - */ -// CXCursor clang_getForStmtInit(CXCursor C); - -/** - * \brief Returns for-loop condition cursor [for(init;cond;inc)], or CXCursor_NoDeclFound if there is no decl, - * or CXCursor_InvalidCode if C is not CXCursor_ForStmt - */ -// CXCursor clang_getForStmtCond(CXCursor C); - -/** - * \brief Returns for-loop increment cursor [for(init;cond;inc)], or CXCursor_NoDeclFound if there is no decl, - * or CXCursor_InvalidCode if C is not CXCursor_ForStmt - */ -// CXCursor clang_getForStmtInc(CXCursor C); - -/** - * \brief Returns for-loop body, or CXCursor_NoDeclFound if there is no decl, - * or CXCursor_InvalidCode if C is not CXCursor_ForStmt - */ -// CXCursor clang_getForStmtBody(CXCursor C); - - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/robloxpyc/swiftparser.swift b/robloxpyc/swiftparser.swift deleted file mode 100644 index d998ad4..0000000 --- a/robloxpyc/swiftparser.swift +++ /dev/null @@ -1,12 +0,0 @@ -import SwiftSyntax - -let source = """ -func greet(name: String) { - print("Hello, \\(name)!") -} -""" - -let parser = SyntaxParser() -let syntax = try parser.parse(source: source) - -print(syntax) diff --git a/robloxpyc/symbolsstack.py b/robloxpyc/symbolsstack.py deleted file mode 100644 index 0747757..0000000 --- a/robloxpyc/symbolsstack.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Class for the symbols stack""" - - -class SymbolsStack: - """Class for the symbols stack""" - def __init__(self): - self.symbols = [[]] - - def add_symbol(self, name): - """Add a new symbol to the curent stack""" - self.symbols[-1].append(name) - - def exists(self, name): - """Check symbol is exists in the current stack""" - for stack in self.symbols: - if name in stack: - return True - return False - - def push(self): - """Push the symbols stack""" - self.symbols.append([]) - - def pop(self): - """Pop the symbols stack""" - self.symbols.pop() diff --git a/robloxpyc/textcompiler.py b/robloxpyc/textcompiler.py deleted file mode 100644 index 154b440..0000000 --- a/robloxpyc/textcompiler.py +++ /dev/null @@ -1,80 +0,0 @@ -import json -import os -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from errormanager import * - from util import * -else: - from .errormanager import * - from .util import * - - -def json_to_lua(json_str): - data = json.loads(json_str) - return _json_to_lua(data) - -def _json_to_lua(data): - if isinstance(data, dict): - items = [] - for key, value in data.items(): - items.append('[{}] = {}'.format(_json_to_lua(key), _json_to_lua(value))) - return '{{{}}}'.format(', '.join(items)) - elif isinstance(data, list): - items = [] - for value in data: - items.append(_json_to_lua(value)) - return '{{{}}}'.format(', '.join(items)) - elif isinstance(data, str): - return '"{}"'.format(data) - else: - return str(data) - - -def unknowncompile(r, file): - if file.endswith(".txt") or ("." not in file): - # This is for text files and files without a file extension - try: - contents = "" - with open(os.path.join(r, file), "r") as f: - contents = f.read() - contents = contents.replace("]]", "]\]") - contents = "--/ Compiled using roblox-pyc | Textfile compiler \--\nlocal file\nfile = {Contents = [["+contents+"]], Type = 'rawtext', Extension = '"+file.split(".")[file.split(".").__len__()-1]+"', SetSource = function(self, input) self.Contents = input end}" - filename = os.path.basename(file) - sepratedbydot = filename.split(".") - ending = sepratedbydot[sepratedbydot.__len__()-1] - newfilename = filename.replace("."+ending, ".lua") - # if newfilename == oldfilename, add .lua to the end. For files without endings - if filename == newfilename: - newfilename = newfilename+".lua" - - open(os.path.join(r, newfilename), "x").close() - with open(os.path.join(r, newfilename), "w") as f: - f.write(contents) - except UnicodeDecodeError: - print(warn("Failed to read "+os.path.join(r, file)+"!")) -def jsoncompile(r, file): - if file.endswith(".json"): - # compile the file to a file with the same name and path but .lua - try: - contents = "" - with open(os.path.join(r, file), "r") as f: - contents = f.read() - contents = "--/ Compiled using roblox-pyc | JSON compiler \--\nreturn {Contents = "+json_to_lua(contents)+", Type = 'json', Extension = 'json', SetSource = function(self, input) self.Contents = input end}" - filename = os.path.basename(file) - sepratedbydot = filename.split(".") - ending = sepratedbydot[sepratedbydot.__len__()-1] - newfilename = filename.replace("."+ending, ".lua") - # if newfilename == oldfilename, add .lua to the end. For files without endings - if filename == newfilename: - newfilename = newfilename+".lua" - if not os.path.exists(os.path.dirname(os.path.join(r, newfilename))): - open(os.path.join(r, newfilename), "x").close() - with open(os.path.join(r, newfilename), "w") as f: - f.write(contents) - except UnicodeDecodeError: - # Just delete the file - print(warn("Failed to read "+os.path.join(r, file)+"!")) -def othercompile(r, file): # Handles Text files and JSON files, and files without a file extension - jsoncompile(r, file) - unknowncompile(r, file) \ No newline at end of file diff --git a/robloxpyc/tokenendmode.py b/robloxpyc/tokenendmode.py deleted file mode 100644 index 9af9de9..0000000 --- a/robloxpyc/tokenendmode.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Token end mode""" -from enum import Enum - - -class TokenEndMode(Enum): - """This enum represents token end mode""" - LINE_FEED = 0 - LINE_CONTINUE = 1 diff --git a/robloxpyc/unaryopdesc.py b/robloxpyc/unaryopdesc.py deleted file mode 100644 index c558d66..0000000 --- a/robloxpyc/unaryopdesc.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Unary operation description""" -import ast - - -_DEFAULT_FORMAT = "{operation}{value}" - - -class UnaryOperationDesc: - """Unary operation description""" - - OPERATION = { - ast.USub: { - "value": "-", - "format": _DEFAULT_FORMAT, - }, - ast.UAdd: { - "value": "", - "format": _DEFAULT_FORMAT, - }, - ast.Not: { - "value": "not", - "format": "not {value}", - }, - ast.Invert: { - "value": "~", - "format": "bit32.bnot({value})", - }, - } diff --git a/robloxpyc/util.py b/robloxpyc/util.py deleted file mode 100644 index 0f1d9bd..0000000 --- a/robloxpyc/util.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Holds many useful functions for roblox-pyc""" -import sys -import os -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - import colortext, configmanager, pytranslator -else: - from . import colortext, configmanager, pytranslator -import os - -def backwordreplace(s, old, new, occurrence): - li = s.rsplit(old, occurrence) - return new.join(li) -def filtercompiledfolder(): - cwd = os.getcwd() - compiled = cwd+"-compiled" - for r, d, f in os.walk(compiled): - for file in f: - if not file.endswith(".lua"): - os.remove(os.path.join(r, file)) - -def onNotFound(target): - currentcommand = sys.argv[2] - - allCLIS = configmanager.getconfig("general", "cli", []) - - # go through allCLIS and check if target and command matches - for i in allCLIS: - if i["target"] == target: - pass -def lib(): - # if /server and /client are found, then error - if os.path.exists(os.path.join(os.getcwd(), "server")) and os.path.exists(os.path.join(os.getcwd(), "client")): - print(colortext.warn("Do not install dependencies inside of the parent folder, rather both the /server and /client folder. Would you like to do this?")) - inputval = input("[Y/n]: ").lower() - if inputval == "n": - sys.exit() - elif inputval == "y": - # Set cwd to server and run lib - os.chdir(os.path.join(os.getcwd(), "server")) - lib() - # set cwd to client and run lib - os.chdir(os.path.join(os.getcwd(), "..", "client")) - lib() - # create dependencies folder if it doesnt exist - if not os.path.exists(os.path.join(os.getcwd(), "dependencies")): - os.makedirs(os.path.join(os.getcwd(), "dependencies")) - - cwd = os.getcwd() - # cwd+sys.argv[2] - dir = os.path.join(cwd,"dependencies", "stdlib.lua") - if not os.path.exists(os.path.dirname(dir)): - open(dir, "x").close() - with open(dir, "w") as f: - translator = pytranslator.Translator() - f.write(translator.get_luainit(configmanager.getconfig("general", "luaext", []))) - # Make a file called content.json in the dependencies folder - open(os.path.join(cwd, "dependencies", "content.json"), "x").close() diff --git a/robloxpyc/wally.py b/robloxpyc/wally.py deleted file mode 100644 index df589e6..0000000 --- a/robloxpyc/wally.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Handles downloading packages from wally.""" - -import sys, os, json, requests, zipfile -if not (os.path.dirname(os.path.abspath(__file__)).startswith(sys.path[-1])): - from errormanager import * -else: - from .errormanager import * - -def wallyget(author, name, isDependant=False): - # Use wally and download the zip and unpack it - print(info(f"Getting @{author}/{name} metadata", "roblox-pyc wally")) - wallyurl = "https://api.wally.run/v1/" - - # first get package metadata should look like: - metadataurl = wallyurl+"/package-metadata/"+author+"/"+name - data = requests.get(metadataurl).text - jsondata = json.loads(data) - - if 'message' in jsondata: - print(error(jsondata["message"])) - print(error("Exiting process", "roblox-pyc wally")) - sys.exit() - jsondata = json.loads(data)["versions"] - #get latest version and dependencies - latestver = jsondata[0] - vernum = latestver["package"]["version"] - dependencies = latestver["dependencies"] - - for i in dependencies: - dependency = dependencies[i] - print("Downloading dependency "+dependency+"...") - wallyget(dependency.split("/")[0], dependency.split("/")[1].split("@")[0], True) - - # Download the package - if not isDependant: - print("\n"*2) - print("Dependencies downloaded, now downloading package...") - print(info(f"Downloading @{author}/{name} v{vernum}", "roblox-pyc wally")) - url = wallyurl+"/package-contents/"+author+"/"+name+"/"+vernum - headers = {"Wally-Version": "1.0.0"} - response = requests.get(url, headers=headers).content - - # create new file in cwd/dependencies called author_name_version.zip and unzip it - print(info("Saving package...", "roblox-pyc wally")) - #### if dependencies folder doesnt exist, create it - if not os.path.exists(os.path.join(os.getcwd(), "dependencies")): - os.makedirs(os.path.join(os.getcwd(), "dependencies")) - #### - open(os.path.join(os.getcwd(), "dependencies", "@"+author+"/"+name+".zip"), "x").close() - with open(os.path.join(os.getcwd(), "dependencies", "@"+author+"/"+name+".zip"), "wb") as file: - file.write(response) - # unzip - print(info("Unzipping package...", "roblox-pyc wally")) - with zipfile.ZipFile(os.path.join(os.getcwd(), "dependencies", "@"+author+"/"+name+".zip"), 'r') as zip_ref: - zip_ref.extractall(os.path.join(os.getcwd(), "dependencies", "@"+author+"/"+name)) - # delete the zip - print(info("Deleting uneeded resources...", "roblox-pyc wally")) - os.remove(os.path.join(os.getcwd(), "dependencies", "@"+author+"/"+name+".zip")) - diff --git a/robloxpyc/writer.py b/robloxpyc/writer.py deleted file mode 100644 index 9302bee..0000000 --- a/robloxpyc/writer.py +++ /dev/null @@ -1,60 +0,0 @@ -########################################################################### -# Code Writer -# -# This is a helper that can be used to write code; it knows how to -# maintain the right number of spaces between code blocks to remain PEP8 -# compliant. -########################################################################### -from __future__ import unicode_literals, print_function - - -class CodeWriter(object): - def __init__(self, out, preamble=None): - self.out = out - self.line_cleared = True - self.blank_lines = 2 - self.depth = 0 - self.empty = True - - if preamble: - self.out.write(preamble) - - def write(self, content): - if not self.empty: - for i in range(0, self.blank_lines): - self.out.write('\n') - self.blank_lines = 0 - if content: - if self.line_cleared: - self.out.write(' ' * self.depth) - self.out.write(content) - self.empty = False - self.line_cleared = False - - def clear_line(self): - if not self.line_cleared: - self.out.write('\n') - self.line_cleared = True - self.blank_lines = 0 - - def clear_minor_block(self): - if not self.line_cleared: - self.out.write('\n') - self.line_cleared = True - while self.blank_lines < 1: - self.blank_lines += 1 - - def clear_major_block(self): - if not self.line_cleared: - self.out.write('\n') - self.line_cleared = True - while self.blank_lines < max(1, 2 - self.depth): - self.blank_lines += 1 - - def start_block(self): - self.empty = True - self.depth += 1 - self.blank_lines = 2 - - def end_block(self): - self.depth -= 1 \ No newline at end of file diff --git a/rojo-test/.gitignore b/rojo-test/.gitignore deleted file mode 100644 index 0e4c27b..0000000 --- a/rojo-test/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Project place file -/rojo-test.rbxlx - -# Roblox Studio lock files -/*.rbxlx.lock -/*.rbxl.lock \ No newline at end of file diff --git a/rojo-test/README.md b/rojo-test/README.md deleted file mode 100644 index 2ae0b09..0000000 --- a/rojo-test/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# rojo-test -Generated by [Rojo](https://github.com/rojo-rbx/rojo) 7.3.0. - -## Getting Started -To build the place from scratch, use: - -```bash -rojo build -o "rojo-test.rbxlx" -``` - -Next, open `rojo-test.rbxlx` in Roblox Studio and start the Rojo server: - -```bash -rojo serve -``` - -For more help, check out [the Rojo documentation](https://rojo.space/docs). \ No newline at end of file diff --git a/rojo-test/default.project.json b/rojo-test/default.project.json deleted file mode 100644 index ea185c3..0000000 --- a/rojo-test/default.project.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "rojo-test", - "tree": { - "$className": "DataModel", - - "ReplicatedStorage": { - "Shared": { - "$path": "src-compiled/shared" - } - }, - - "ServerScriptService": { - "Server": { - "$path": "src-compiled/server" - } - }, - - "StarterPlayer": { - "StarterPlayerScripts": { - "Client": { - "$path": "src-compiled/client" - } - } - }, - - "Workspace": { - "$properties": { - "FilteringEnabled": true - }, - "Baseplate": { - "$className": "Part", - "$properties": { - "Anchored": true, - "Color": [ - 0.38823, - 0.37254, - 0.38823 - ], - "Locked": true, - "Position": [ - 0, - -10, - 0 - ], - "Size": [ - 512, - 20, - 512 - ] - } - } - }, - "Lighting": { - "$properties": { - "Ambient": [ - 0, - 0, - 0 - ], - "Brightness": 2, - "GlobalShadows": true, - "Outlines": false, - "Technology": "Voxel" - } - }, - "SoundService": { - "$properties": { - "RespectFilteringEnabled": true - } - } - } -} \ No newline at end of file diff --git a/rojo-test/default.project.lua b/rojo-test/default.project.lua deleted file mode 100644 index b532454..0000000 --- a/rojo-test/default.project.lua +++ /dev/null @@ -1,2 +0,0 @@ ---/ Compiled using roblox-pyc | JSON compiler \-- -return {Contents = {["name"] = "rojo-test", ["tree"] = {["$className"] = "DataModel", ["ReplicatedStorage"] = {["Shared"] = {["$path"] = "src-compiled/shared"}}, ["ServerScriptService"] = {["Server"] = {["$path"] = "src-compiled/server"}}, ["StarterPlayer"] = {["StarterPlayerScripts"] = {["Client"] = {["$path"] = "src-compiled/client"}}}, ["Workspace"] = {["$properties"] = {["FilteringEnabled"] = True}, ["Baseplate"] = {["$className"] = "Part", ["$properties"] = {["Anchored"] = True, ["Color"] = {0.38823, 0.37254, 0.38823}, ["Locked"] = True, ["Position"] = {0, -10, 0}, ["Size"] = {512, 20, 512}}}}, ["Lighting"] = {["$properties"] = {["Ambient"] = {0, 0, 0}, ["Brightness"] = 2, ["GlobalShadows"] = True, ["Outlines"] = False, ["Technology"] = "Voxel"}}, ["SoundService"] = {["$properties"] = {["RespectFilteringEnabled"] = True}}}}, Type = 'json', Extension = 'json', SetSource = function(self, input) self.Contents = input end} \ No newline at end of file diff --git a/rojo-test/src-compiled/client/init.client.lua b/rojo-test/src-compiled/client/init.client.lua deleted file mode 100644 index e8ffca1..0000000 --- a/rojo-test/src-compiled/client/init.client.lua +++ /dev/null @@ -1,22 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -print("Hello!") - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/rojo-test/src-compiled/server/init.server.lua b/rojo-test/src-compiled/server/init.server.lua deleted file mode 100644 index 8a66a12..0000000 --- a/rojo-test/src-compiled/server/init.server.lua +++ /dev/null @@ -1,28 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local id = builtin.id -local shared = builtin.shared -local int = builtin.int -local print = builtin.print -local os = builtin.os - ------------------------------------------------------------------------------ -local Fluids = import("shared.Hello", "FluidCalculation") -local newFluid = Fluids(10, 10, 10, 10, 10) -newFluid.step(10) -print(newFluid.width, newFluid.height, newFluid.depth, newFluid.viscosity, newFluid.density, newFluid.velocity, newFluid.pressure) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/rojo-test/src-compiled/shared/metadata.lua b/rojo-test/src-compiled/shared/metadata.lua deleted file mode 100644 index 3c00eb4..0000000 --- a/rojo-test/src-compiled/shared/metadata.lua +++ /dev/null @@ -1,2 +0,0 @@ ---/ Compiled using roblox-pyc | JSON compiler \-- -return {Contents = {["default"] = {["density"] = 1.0, ["viscosity"] = 1.0, ["width"] = 1.0, ["height"] = 1.0, ["depth"] = 1.0}}, Type = 'json', Extension = 'json', SetSource = function(self, input) self.Contents = input end} \ No newline at end of file diff --git a/rojo-test/src/.rpyc b/rojo-test/src/.rpyc deleted file mode 100644 index e69de29..0000000 diff --git a/rojo-test/src/client/init.client.lua b/rojo-test/src/client/init.client.lua deleted file mode 100644 index e8ffca1..0000000 --- a/rojo-test/src/client/init.client.lua +++ /dev/null @@ -1,22 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -print("Hello!") - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/rojo-test/src/client/init.client.py b/rojo-test/src/client/init.client.py deleted file mode 100644 index f8f41c4..0000000 --- a/rojo-test/src/client/init.client.py +++ /dev/null @@ -1 +0,0 @@ -print("Hello!") \ No newline at end of file diff --git a/rojo-test/src/server/init.server.lua b/rojo-test/src/server/init.server.lua deleted file mode 100644 index 8a66a12..0000000 --- a/rojo-test/src/server/init.server.lua +++ /dev/null @@ -1,28 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local id = builtin.id -local shared = builtin.shared -local int = builtin.int -local print = builtin.print -local os = builtin.os - ------------------------------------------------------------------------------ -local Fluids = import("shared.Hello", "FluidCalculation") -local newFluid = Fluids(10, 10, 10, 10, 10) -newFluid.step(10) -print(newFluid.width, newFluid.height, newFluid.depth, newFluid.viscosity, newFluid.density, newFluid.velocity, newFluid.pressure) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/rojo-test/src/server/init.server.py b/rojo-test/src/server/init.server.py deleted file mode 100644 index f33c76f..0000000 --- a/rojo-test/src/server/init.server.py +++ /dev/null @@ -1,5 +0,0 @@ -from shared.Hello import FluidCalculation as Fluids - -newFluid = Fluids(10, 10, 10, 10, 10) -newFluid.step(10) -print(newFluid.width, newFluid.height, newFluid.depth, newFluid.viscosity, newFluid.density, newFluid.velocity, newFluid.pressure) \ No newline at end of file diff --git a/rojo-test/src/shared/Hello.py b/rojo-test/src/shared/Hello.py deleted file mode 100644 index 37715f2..0000000 --- a/rojo-test/src/shared/Hello.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Simple fluid simulation 3d, based on the Navier-Stokes equations. -""" -from . import metadata as profiles -class FluidCalculation: - def __init__(self, width, height, depth, viscosity, density): - self.width = width or profiles.default.width - self.height = height or profiles.default.height - self.depth = depth or profiles.default.depth - self.viscosity = viscosity or profiles.default.viscosity - self.density = density or profiles.default.density - self.velocity = [[[0.0 for z in range(depth)] for y in range(height)] for x in range(width)] - self.pressure = [[[0.0 for z in range(depth)] for y in range(height)] for x in range(width)] - - def step(self, dt): - # Calculate velocity - for x in range(1, self.width - 1): - for y in range(1, self.height - 1): - for z in range(1, self.depth - 1): - u = self.velocity[x][y][z][0] - v = self.velocity[x][y][z][1] - w = self.velocity[x][y][z][2] - u += dt * (-u * (u - self.velocity[x - 1][y][z][0]) - - v * (u - self.velocity[x][y - 1][z][0]) - - w * (u - self.velocity[x][y][z - 1][0]) + - self.viscosity * ((self.velocity[x + 1][y][z][0] + - self.velocity[x - 1][y][z][0] + - self.velocity[x][y + 1][z][0] + - self.velocity[x][y - 1][z][0] + - self.velocity[x][y][z + 1][0] + - self.velocity[x][y][z - 1][0]) - - 6 * u)) - v += dt * (-u * (v - self.velocity[x - 1][y][z][1]) - - v * (v - self.velocity[x][y - 1][z][1]) - - w * (v - self.velocity[x][y][z - 1][1]) + - self.viscosity * ((self.velocity[x + 1][y][z][1] + - self.velocity[x - 1][y][z][1] + - self.velocity[x][y + 1][z][1] + - self.velocity[x][y - 1][z][1] + - self.velocity[x][y][z + 1][1] + - self.velocity[x][y][z - 1][1]) - - 6 * v)) - w += dt * (-u * (w - self.velocity[x - 1][y][z][2]) - - v * (w - self.velocity[x][y - 1][z][2]) - - w * (w - self.velocity[x][y][z - 1][2]) + - self.viscosity * ((self.velocity[x + 1][y][z][2] + - self.velocity[x - 1][y][z][2] + - self.velocity[x][y + 1][z][2] + - self.velocity[x][y - 1][z][2] + - self.velocity[x][y][z + 1][2] + - self.velocity[x][y][z - 1][2]) - - 6 * w)) - self.velocity[x][y][z][0] = u - self.velocity[x][y][z][1] = v - self.velocity[x][y][z][2] = w - - # Calculate pressure - for i in range(20): - for x in range(1, self.width - 1): - for y in range(1, self.height - 1): - for z in range(1, self.depth - 1): - self.pressure[x][y][z] = ((self.pressure[x + 1][y][z] + - self.pressure[x - 1][y][z] + - self.pressure[x][y + 1][z] + - self.pressure[x][y - 1][z] + - self.pressure[x][y][z + 1] + - self.pressure[x][y][z - 1]) + - self.density * (self.velocity[x][y][z][0] - - self.velocity[x - 1][y][z][0] + - self.velocity[x][y][z][1] - - self.velocity[x][y - 1][z][1] + - self.velocity[x][y][z][2] - - self.velocity[x][y][z - 1][2])) / 6.0 - - # Update velocity - for x in range(1, self.width - 1): - for y in range(1, self.height - 1): - for z in range(1, self.depth - 1): - self.velocity[x][y][z][0] -= dt * (self.pressure[x + 1][y][z] - - self.pressure[x - 1][y][z]) / (2.0 * self.density) - self.velocity[x][y][z][1] -= dt * (self.pressure[x][y + 1][z] - - self.pressure[x][y - 1][z]) / (2.0 * self.density) - self.velocity[x][y][z][2] -= dt * (self.pressure[x][y][z + 1] - - self.pressure[x][y][z - 1]) / (2.0 * self.density) \ No newline at end of file diff --git a/rojo-test/src/shared/metadata.json b/rojo-test/src/shared/metadata.json deleted file mode 100644 index f428ed3..0000000 --- a/rojo-test/src/shared/metadata.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "default": { - "density": 1.0, - "viscosity": 1.0, - "width": 1.0, - "height": 1.0, - "depth": 1.0 - } -} \ No newline at end of file diff --git a/rojo-test/src/shared/metadata.lua b/rojo-test/src/shared/metadata.lua deleted file mode 100644 index 3c00eb4..0000000 --- a/rojo-test/src/shared/metadata.lua +++ /dev/null @@ -1,2 +0,0 @@ ---/ Compiled using roblox-pyc | JSON compiler \-- -return {Contents = {["default"] = {["density"] = 1.0, ["viscosity"] = 1.0, ["width"] = 1.0, ["height"] = 1.0, ["depth"] = 1.0}}, Type = 'json', Extension = 'json', SetSource = function(self, input) self.Contents = input end} \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index bd30bc8..0000000 --- a/setup.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[metadata] -name = roblox-pyc -version = 2.26.113 - -[options] -packages = robloxpyc - - -[options.entry_points] -console_scripts = - rblx-py = robloxpyc.robloxpy:w - rblx-c = robloxpyc.robloxpy:candcpperror - rblx-cpp = robloxpyc.robloxpy:candcpperror - rblx-lunar = robloxpyc.robloxpy:lunar - rblx-pyc = robloxpyc.robloxpy:pyc - - rpyc = robloxpyc.robloxpy:pyc - - rbxpyc = robloxpyc.robloxpy:pyc - rbxlun = robloxpyc.robloxpy:lunar - rbxpy = robloxpyc.robloxpy:w - rbxc = robloxpyc.robloxpy:candcpperror - rbxcpp = robloxpyc.robloxpy:candcpperror diff --git a/setup.py b/setup.py deleted file mode 100644 index dd2f9cf..0000000 --- a/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -from setuptools import setup, find_packages - - -# metadata goes here, =) -setup(install_requires=[ - 'clang', - 'libclang', - 'typer', - 'flask', - 'pyflakes', - 'pyyaml', - 'tqdm', - 'requests', - 'packaging' - ], - name = 'roblox-pyc', - description='The Python, Lunar, C, C++ to Roblox Lua compiler', - url="https://github.com/AsynchronousAI/roblox.pyc", - long_description=open('README.md').read(), - long_description_content_type='text/markdown', - include_package_data=True, - packages=find_packages(), - author='roblox-pyc team', - author_email="roblox.pyc@gmail.com", - license="GNU AFFERO GENERAL PUBLIC LICENSE", - ) diff --git a/src/rbxpy.py b/src/rbxpy.py new file mode 100644 index 0000000..c54fe4d --- /dev/null +++ b/src/rbxpy.py @@ -0,0 +1,2253 @@ +#!/usr/bin/env python3 +import sys, ast, yaml, re, os, subprocess +from pprint import pprint +from pathlib import Path +from enum import Enum + +#### CONSTANTS #### +VERSION = "3.0.0" +TAB = "\t\b\b\b\b" + +#### COMPILER #### +"""Config""" +class Config: + """Translator config.""" + def __init__(self, filename=None): + self.data = { + "class": { + "return_at_the_end": False, + }, + } + + if filename is not None: + self.load(filename) + + def load(self, filename): + """Load config from the file""" + try: + with open(filename, "r") as stream: + data = yaml.load(stream) + self.data.update(data) + except FileNotFoundError: + pass # Use a default config if the file not found + except yaml.YAMLError as ex: + print(ex) + + def __getitem__(self, key): + """Get data values""" + return self.data[key] + +"""Binary operation description""" +_DEFAULT_BIN_FORMAT = "{left} {operation} {right}" + + +class BinaryOperationDesc: + """Binary operation description""" + + OPERATION = { + ast.Add: { + "value": "+", + "format": "(safeadd({left}, {right}))", + "depend": "safeadd", + }, + ast.Sub: { + "value": "-", + "format": _DEFAULT_BIN_FORMAT, + "depend": "", + }, + ast.Mult: { + "value": "*", + "format": _DEFAULT_BIN_FORMAT, + "depend": "", + }, + ast.Div: { + "value": "/", + "format": _DEFAULT_BIN_FORMAT, + "depend": "", + }, + ast.Mod: { + "value": "%", + "format": _DEFAULT_BIN_FORMAT, + "depend": "", + }, + ast.Pow: { + "value": "^", + "format": _DEFAULT_BIN_FORMAT, + "depend": "", + }, + ast.FloorDiv: { + "value": "/", + "format": "math.floor({left} {operation} {right})", + "depend": "", + }, + ast.LShift: { + "value": "", + "format": "bit32.lshift({left}, {right})", + "depend": "", + }, + ast.RShift: { + "value": "", + "format": "bit32.rshift({left}, {right})", + "depend": "", + }, + ast.BitOr: { + "value": "", + "format": "bit32.bor({left}, {right})", + "depend": "", + }, + ast.BitAnd: { + "value": "", + "format": "bit32.band({left}, {right})", + "depend": "", + }, + ast.BitXor: { + "value": "", + "format": "bit32.bxor({left}, {right})", + "depend": "", + }, + } +"""Boolean operation description""" +_DEFAULT_BOOL_FORMAT = "{left} {operation} {right}" + + +class BooleanOperationDesc: + """Binary operation description""" + + OPERATION = { + ast.And: { + "value": "and", + "format": _DEFAULT_BOOL_FORMAT, + }, + ast.Or: { + "value": "or", + "format": _DEFAULT_BOOL_FORMAT, + }, + } + +"""Compare operation description""" + +class CompareOperationDesc: + """Compare operation description""" + + OPERATION = { + ast.Eq: "==", + ast.NotEq: "~=", + ast.Lt: "<", + ast.LtE: "<=", + ast.Gt: ">", + ast.GtE: ">=", + ast.In: { + "format": "op_in({left}, {right})", + "depend": "in", + }, + ast.NotIn: { + "format": "not op_in({left}, {right})", + "depend": "in", + }, + } + +"""Name constant description""" + + +class NameConstantDesc: + """Name constant description""" + + NAME = { + None: "nil", + True: "true", + False: "false", + } + +"""Unary operation description""" + +_DEFAULT_UN_FORMAT = "{operation}{value}" + + +class UnaryOperationDesc: + """Unary operation description""" + + OPERATION = { + ast.USub: { + "value": "-", + "format": _DEFAULT_UN_FORMAT, + }, + ast.UAdd: { + "value": "", + "format": _DEFAULT_UN_FORMAT, + }, + ast.Not: { + "value": "not", + "format": "not {value}", + }, + ast.Invert: { + "value": "~", + "format": "bit32.bnot({value})", + }, + } + +"""Token end mode""" + +class TokenEndMode(Enum): + """This enum represents token end mode""" + LINE_FEED = 0 + LINE_CONTINUE = 1 + +"""Class for the symbols stack""" +class SymbolsStack: + """Class for the symbols stack""" + def __init__(self): + self.symbols = [[]] + + def add_symbol(self, name): + """Add a new symbol to the curent stack""" + self.symbols[-1].append(name) + + def exists(self, name): + """Check symbol is exists in the current stack""" + for stack in self.symbols: + if name in stack: + return True + return False + + def push(self): + """Push the symbols stack""" + self.symbols.append([]) + + def pop(self): + """Pop the symbols stack""" + self.symbols.pop() + +"""Class to store the python code context""" +class Context: + """Class to store the python code context""" + def __init__(self, values=None): + values = values if values is not None else { + "token_end_mode": TokenEndMode.LINE_FEED, + "class_name": "", + "locals": SymbolsStack(), + "globals": SymbolsStack(), # Not working yet + "loop_label_name": "", + "docstring": False, + } + + self.ctx_stack = [values] + + def last(self): + """Return actual context state""" + return self.ctx_stack[-1] + + def push(self, values): + """Push new context state with new values""" + value = self.ctx_stack[-1].copy() + value.update(values) + self.ctx_stack.append(value) + + def pop(self): + """Pop last context state""" + assert len(self.ctx_stack) > 1, "Pop context failed. This is a last context in the stack." + return self.ctx_stack.pop() + +"""Label counter for the loops continue""" +class LoopCounter: + """Loop counter""" + COUNTER = 0 + + @staticmethod + def get_next(): + """Return next loop continue label name""" + LoopCounter.COUNTER += 1 + return "loop_label_{}".format(LoopCounter.COUNTER) + +"""Node visitor""" +dependencies = [] +exports = [] + +class NodeVisitor(ast.NodeVisitor): + LUACODE = "luau" + + """Node visitor""" + def __init__(self, context=None, config=None): + self.context = context if context is not None else Context() + self.config = config + self.last_end_mode = TokenEndMode.LINE_FEED + self.output = [] + + def visit_YieldFrom(self, node): + """Visit yield from""" + self.emit("for _, v in {} do coroutine.yield(v) end".format(self.visit_all(node.value, inline=True))) + + def visit_Assign(self, node): + """Visit assign""" + target = self.visit_all(node.targets[0], inline=True) + value = self.visit_all(node.value, inline=True) + + local_keyword = "" + + last_ctx = self.context.last() + + if last_ctx["class_name"]: + target = ".".join([last_ctx["class_name"], target]) + + if "." not in target and not last_ctx["locals"].exists(target): + local_keyword = "local " + last_ctx["locals"].add_symbol(target) + + + self.emit("{local}{target} = {value}".format(local=local_keyword, + target=target, + value=value)) + + #exports.append(target) + + ### MATCHES ### + def visit_Match(self, node): + """Visit match""" + for case in node.cases: + if hasattr(case.pattern, "value"): + first = "" + if case is node.cases[0]: + first = "" + else: + first = "else" + + val = case.pattern.value.s + if isinstance(val, str): + val = '"{}"'.format(val) + self.emit("{}if {} == {} then".format(first, self.visit_all(node.subject, inline=True), val)) + self.visit_all(case.body) + else: + # self.emit("else") + # self.visit_all(case.body) + error("Match statement requires a compile-time constant, not a variable.") + self.emit("end") + + def visit_MatchValue(self, node): + """Visit match value""" + return self.visit_all(node.value, inline=True) + def visit_MatchCase(self, node): + """Visit match case""" + return self.visit_all(node.body) + + def visit_MatchPattern(self, node): + """Visit match pattern""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchSingleton(self, node): + """Visit match singleton""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchSequence(self, node): + """Visit match sequence""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchMapping(self, node): + """Visit match mapping""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchClass(self, node): + """Visit match class""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchAs(self, node): + """Visit match as""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchKeyword(self, node): + """Visit match keyword""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchStar(self, node): + """Visit match star""" + return self.visit_all(node.pattern, inline=True) + + def visit_MatchOr(self, node): + """Visit match or""" + return self.visit_all(node.pattern, inline=True) + + ### END MATCH ### + def visit_AsyncWith(self, node): + """Visit async with""" + """Visit with""" + self.emit("task.spawn(function()") + self.visit_all(node.body) + body = self.output[-1] + lines = [] + for i in node.items: + line = "" + if i.optional_vars is not None: + line = "local {} = " + line = line.format(self.visit_all(i.optional_vars, + inline=True)) + line += self.visit_all(i.context_expr, inline=True) + lines.append(line) + for line in lines: + body.insert(0, line) + self.emit("end)") + + def visit_Slice(self, node): + """Visit slice""" + error("syntax based slicing is not supported yet. Use slice(, , , ) instead.") + + def visit_JoinedStr(self, node): + # f"{a} {b}" + # becomes + # `{a} {b}` + + """Visit joined string""" + values = [] + for value in node.values: + if isinstance(value, ast.Str): + values.append(value.s) + else: + values.append(self.visit_all(value, inline=True)) + self.emit("`{}`".format("".join(values))) + + def visit_FormattedValue(self, node): + """Visit formatted value""" + # f"{a}" + # becomes + # {a} + self.emit("{" + (self.visit_all(node.value, inline=True)) + "}") + + def visit_Bytes(self, node): + """Visit bytes""" + # Use utf8 strings instead of bytes + self.emit("[[{}]]".format(node.s.decode("utf8"))) + + + def visit_TryStar(self, node): + """Visit try""" + self.emit("local success, result = pcall(function()") + self.visit_all(node.body) + self.emit("end)") + + def visit_Assert(self, node): + """Visit assert""" + self.emit("assert({})".format(self.visit_all(node.test, True))) + + def visit_Nonlocal(self, node): + """Visit nonlocal""" + for name in node.names: + self.context.last()["nonlocals"].add_symbol(name) + + def visit_AnnAssign(self, node): + """Visit annassign""" + target = self.visit_all(node.target, inline=True) + value = self.visit_all(node.value, inline=True) + local_keyword = "" + last_ctx = self.context.last() + istype = (last_ctx["class_name"] == "TYPE") + if last_ctx["class_name"] and not istype: + target = ".".join([last_ctx["class_name"], target]) + if "." not in target and not last_ctx["locals"].exists(target): + local_keyword = "local " + last_ctx["locals"].add_symbol(target) + type = self.visit_all(node.annotation, inline=True) + + if type == "int" or type == "float": + type = "number" + elif type == "str": + type = "string" + elif type == "list" or type == "dict" or type == "memoryview" or type == "bytearray" or type == "set" or type == "range" or type == "frozenset" or type == "module" or type == "classobj" or type == "class" or type == "tuple": + type = "table" + elif type == "NoneType": + type = "nil" + elif type == "ellipsis" or type == "NotImplementedType" or type == "slice" or type == "classmethod" or type == "type" or type == "staticmethod": + error("The Python type '{}' can not be converted to Luau.".format(type)) + + if value != None and value != "": + self.emit("{local}{target}: {type} = {value}".format(local=local_keyword, + target=target, + value=value, + type=type)) + else: + if istype: + self.emit("{target}: {type},".format(local=local_keyword, + target=target, + type=type)) + else: + if node.annotation.__class__.__name__ == "Call": + self.visit_Call(node.annotation, target) + else: + self.emit("{local}{target} = nil".format(local=local_keyword, + target=target, + type=type)) + # example input: + # a: int = 1 + # example output: + # local a = 1 + + def visit_AugAssign(self, node): + """Visit augassign""" + operation = BinaryOperationDesc.OPERATION[node.op.__class__] + + if operation["depend"]: + self.depend(operation["depend"]) + + target = self.visit_all(node.target, inline=True) + + values = { + "left": target, + "right": self.visit_all(node.value, inline=True), + "operation": operation["value"], + } + + line = "({})".format(operation["format"]) + #if operation["depend"]: + # self.depend(operation["depend"]) + line = line.format(**values) + + self.emit("{target} = {line}".format(target=target, line=line)) + + def visit_Attribute(self, node): + """Visit attribute""" + line = "{object}.{attr}" + values = { + "object": self.visit_all(node.value, True), + "attr": node.attr, + } + # Does object start and end with a " " + if (values["object"].startswith('"') and values["object"].endswith('"')) or (values["object"].startswith('\'') and values["object"].endswith('\'')) or (values["object"].startswith('{') and values["object"].endswith('}')) or (values["object"].startswith('[') and values["object"].endswith(']')) or (values["object"].startswith('`') and values["object"].endswith('`')): + values["object"] = "({})".format(values["object"]) + + self.emit(line.format(**values)) + + def visit_BinOp(self, node): + """Visit binary operation""" + operation = BinaryOperationDesc.OPERATION[node.op.__class__] + + if operation["depend"]: + self.depend(operation["depend"]) + + line = "({})".format(operation["format"]) + #if operation["depend"]: Binary operators do not have it + # self.depend(operation["depend"]) + values = { + "left": self.visit_all(node.left, True), + "right": self.visit_all(node.right, True), + "operation": operation["value"], + } + + self.emit(line.format(**values)) + + def visit_BoolOp(self, node): + """Visit boolean operation""" + operation = BooleanOperationDesc.OPERATION[node.op.__class__] + line = "({})".format(operation["format"]) + #if operation["depend"]: + # self.depend(operation["depend"]) + values = { + "left": self.visit_all(node.values[0], True), + "right": self.visit_all(node.values[1], True), + "operation": operation["value"], + } + + self.emit(line.format(**values)) + + def visit_Break(self, node): + """Visit break""" + self.emit("break") + + def visit_Call(self, node, method = None): + """Visit function call""" + line = "{name}({arguments})" + + name = self.visit_all(node.func, inline=True) + if method: + name = method + ":" + name + arguments = [self.visit_all(arg, inline=True) for arg in node.args] + + self.emit(line.format(name=name, arguments=", ".join(arguments))) + + def visit_ClassDef(self, node): + """Visit class definition""" + bases = [self.visit_all(base, inline=True) for base in node.bases] + + if "type" in bases: + self.emit("type {} = {{".format(node.name, self.visit_all(node.bases[0], inline=True))) + self.context.push({"class_name": "TYPE"}) + self.visit_all(node.body) + self.context.pop() + self.emit("}") + else: + local_keyword = "" + last_ctx = self.context.last() + if not last_ctx["class_name"] and not last_ctx["locals"].exists(node.name): + local_keyword = "local " + last_ctx["locals"].add_symbol(node.name) + + name = node.name + if last_ctx["class_name"]: + name = ".".join([last_ctx["class_name"], name]) + + values = { + "local": local_keyword, + "name": name, + "node_name": node.name, + } + + self.emit("{local}{name} = class(function({node_name})".format(**values)) + self.depend("class") + + self.context.push({"class_name": node.name}) + self.visit_all(node.body) + self.context.pop() + + self.output[-1].append("return {node_name}".format(**values)) + + self.emit("end, {{{}}})".format(", ".join(bases))) + + # Return class object only in the top-level classes. + # Not in the nested classes. + if self.config["class"]["return_at_the_end"] and not last_ctx["class_name"]: + self.emit("return {}".format(name)) + + def visit_Compare(self, node): + """Visit compare""" + + line = "" + + left = self.visit_all(node.left, inline=True) + for i in range(len(node.ops)): + operation = node.ops[i] + operation = CompareOperationDesc.OPERATION[operation.__class__] + + right = self.visit_all(node.comparators[i], inline=True) + + values = { + "left": left, + "right": right, + } + + if isinstance(operation, str): + values["op"] = operation + line += "{left} {op} {right}".format(**values) + elif isinstance(operation, dict): + line += operation["format"].format(**values) + if operation["depend"]: + self.depend(operation["depend"]) + + if i < len(node.ops) - 1: + left = right + line += " and " + + self.emit("({})".format(line)) + + def visit_Continue(self, node): + """Visit continue""" + last_ctx = self.context.last() + line = "continue" + self.emit(line) + + def visit_Delete(self, node): + """Visit delete""" + targets = [self.visit_all(target, inline=True) for target in node.targets] + nils = ["nil" for _ in targets] + line = "{targets} = {nils}".format(targets=", ".join(targets), + nils=", ".join(nils)) + self.emit(line) + + def visit_Dict(self, node): + """Visit dictionary""" + keys = [] + + for key in node.keys: + value = self.visit_all(key, inline=True) + if isinstance(key, ast.Str): + value = "[{}]".format(value) + keys.append(value) + + values = [self.visit_all(item, inline=True) for item in node.values] + + elements = ["{} = {}".format(keys[i], values[i]) for i in range(len(keys))] + elements = ", ".join(elements) + self.depend("dict") + self.emit("dict {{{}}}".format(elements)) + self.depend("dict") + + def visit_DictComp(self, node): + """Visit dictionary comprehension""" + self.emit("(function()") + self.depend("dict") + self.emit("local result = dict {}") + self.depend("dict") + + ends_count = 0 + + for comp in node.generators: + line = "for {target} in {iterator} do" + values = { + "target": self.visit_all(comp.target, inline=True), + "iterator": self.visit_all(comp.iter, inline=True), + } + line = line.format(**values) + self.emit(line) + ends_count += 1 + + for if_ in comp.ifs: + line = "if {} then".format(self.visit_all(if_, inline=True)) + self.emit(line) + ends_count += 1 + + line = "result[{key}] = {value}" + values = { + "key": self.visit_all(node.key, inline=True), + "value": self.visit_all(node.value, inline=True), + } + self.emit(line.format(**values)) + + self.emit(" ".join(["end"] * ends_count)) + + self.emit("return result") + self.emit("end)()") + + def visit_Ellipsis(self, node): + """Visit ellipsis""" + self.emit("...") + + def visit_Expr(self, node): + """Visit expr""" + expr_is_docstring = False + if isinstance(node.value, ast.Str): + expr_is_docstring = True + + self.context.push({"docstring": expr_is_docstring}) + output = self.visit_all(node.value) + self.context.pop() + + self.output.append(output) + + def visit_FunctionDef(self, node): + """Visit function definition""" + line = "{local}function {name}({arguments})" + + last_ctx = self.context.last() + + name = node.name + type = 1 # 1 = static, 2 = class + for decorator in reversed(node.decorator_list): + decorator_name = self.visit_all(decorator, inline=True) + + if decorator_name == "classmethod": + type = 2 + elif decorator_name == "staticmethod": + type = 1 + if last_ctx["class_name"]: + name = ".".join([last_ctx["class_name"], name]) + + if type == 1: + arguments = [arg.arg for arg in node.args.args] + else: + arguments = ["self"] + arguments.extend([arg.arg for arg in node.args.args]) + + if node.args.vararg is not None: + arguments.append("...") + + local_keyword = "" + + if "." not in name and not last_ctx["locals"].exists(name): + local_keyword = "local " + last_ctx["locals"].add_symbol(name) + + function_def = line.format(local=local_keyword, + name=name, + arguments=", ".join(arguments)) + + self.emit(function_def) + + self.context.push({"class_name": ""}) + self.visit_all(node.body) + self.context.pop() + + body = self.output[-1] + + if node.args.vararg is not None: + self.depend("list") + line = "local {name} = list({{...})".format(name=node.args.vararg.arg) + body.insert(0, line) + + arg_index = -1 + for i in reversed(node.args.defaults): + line = "{name} = {name} or {value}" + + arg = node.args.args[arg_index] + values = { + "name": arg.arg, + "value": self.visit_all(i, inline=True), + } + body.insert(0, line.format(**values)) + + arg_index -= 1 + + self.emit("end") + + for decorator in reversed(node.decorator_list): + decorator_name = self.visit_all(decorator, inline=True) + if decorator_name == "classmethod" or decorator_name == "staticmethod": + continue + values = { + "name": name, + "decorator": decorator_name, + } + line = "{name} = {decorator}:Connect({name})".format(**values) + self.emit(line) + + #exports.append(name) + + def visit_For(self, node): + """Visit for loop""" + line = "for {target} in {iter} do" + + values = { + "target": self.visit_all(node.target, inline=True), + "iter": self.visit_all(node.iter, inline=True), + } + + self.emit(line.format(**values)) + + continue_label = LoopCounter.get_next() + self.context.push({ + "loop_label_name": continue_label, + }) + self.visit_all(node.body) + self.context.pop() + + self.emit("end") + + def visit_Global(self, node): + """Visit globals""" + last_ctx = self.context.last() + for name in node.names: + last_ctx["globals"].add_symbol(name) + exports.append(name) + + def visit_AsyncFunctionDef(self, node): + """Visit async function definition""" + line = "{local}function {name}({arguments}) task.spawn(function()" + + last_ctx = self.context.last() + + name = node.name + type = 1 # 1 = static, 2 = class + for decorator in reversed(node.decorator_list): + decorator_name = self.visit_all(decorator, inline=True) + + if decorator_name == "classmethod": + type = 2 + elif decorator_name == "staticmethod": + type = 1 + if last_ctx["class_name"]: + name = ".".join([last_ctx["class_name"], name]) + + if type == 1: + arguments = [arg.arg for arg in node.args.args] + else: + arguments = ["self"] + arguments.extend([arg.arg for arg in node.args.args]) + + if node.args.vararg is not None: + arguments.append("...") + + local_keyword = "" + + if "." not in name and not last_ctx["locals"].exists(name): + local_keyword = "local " + last_ctx["locals"].add_symbol(name) + + function_def = line.format(local=local_keyword, + name=name, + arguments=", ".join(arguments)) + + self.emit(function_def) + + self.context.push({"class_name": ""}) + self.visit_all(node.body) + self.context.pop() + + body = self.output[-1] + + if node.args.vararg is not None: + self.depend("list") + line = "local {name} = list({{...})".format(name=node.args.vararg.arg) + body.insert(0, line) + + arg_index = -1 + for i in reversed(node.args.defaults): + line = "{name} = {name} or {value}" + + arg = node.args.args[arg_index] + values = { + "name": arg.arg, + "value": self.visit_all(i, inline=True), + } + body.insert(0, line.format(**values)) + + arg_index -= 1 + + self.emit("end) end") + + for decorator in reversed(node.decorator_list): + decorator_name = self.visit_all(decorator, inline=True) + if decorator_name == "classmethod" or decorator_name == "staticmethod": + continue + values = { + "name": name, + "decorator": decorator_name, + } + line = "{name} = {decorator}:Connect({name})".format(**values) + self.emit(line) + + #exports.append(name) + def visit_Await(self, node): + """Visit await""" + self.emit("coroutine.await({})".format(self.visit_all(node.value, inline=True))) + + def visit_Yield(self, node): + """Visit yield""" + self.emit("coroutine.yield({})".format(self.visit_all(node.value, inline=True))) + + def visit_If(self, node): + """Visit if""" + test = self.visit_all(node.test, inline=True) + + line = "if {} then".format(test) + + self.emit(line) + self.visit_all(node.body) + + if node.orelse: + if isinstance(node.orelse[0], ast.If): + elseif = node.orelse[0] + elseif_test = self.visit_all(elseif.test, inline=True) + + line = "elseif {} then".format(elseif_test) + self.emit(line) + + output_length = len(self.output) + self.visit_If(node.orelse[0]) + + del self.output[output_length] + del self.output[-1] + else: + self.emit("else") + self.visit_all(node.orelse) + + self.emit("end") + + def visit_IfExp(self, node): + """Visit if expression""" + line = "{cond} and {true_cond} or {false_cond}" + values = { + "cond": self.visit_all(node.test, inline=True), + "true_cond": self.visit_all(node.body, inline=True), + "false_cond": self.visit_all(node.orelse, inline=True), + } + + self.emit(line.format(**values)) + + def visit_Import(self, node): + """Visit import""" + line = 'local {asname} = require("{name}")' + values = {"asname": "", "name": ""} + + if node.names[0].name.startswith("game."): + line = 'local {asname} = game:GetService("{name}")' + values["name"] = node.names[0].name[5:] + + if node.names[0].asname is None: + if not node.names[0].name.startswith("game."): + values["name"] = node.names[0].name + values["asname"] = values["name"] + values["asname"] = values["asname"].split(".")[-1] + else: + values["asname"] = node.names[0].asname + if not node.names[0].name.startswith("game."): + values["name"] = node.names[0].name + + self.emit(line.format(**values)) + + def visit_ImportFrom(self, node): + """Visit import from""" + module = node.module + if module is None: + module = "" + else: + module = module + + if module == "services": + for name in node.names: + if name.asname is None: + if name.name == "*": + error("import * is unsupproted") + else: + self.emit("local {name} = game:GetService(\"{name}\")".format( + name=name.name, + module=module, + )) + else: + if name.name == "*": + error("import * is unsupproted") + else: + self.emit("local {name} = game:GetService(\"{realname}\")".format( + name=name.asname, + module=module, + realname=name.name, + )) + else: + for name in node.names: + if name.asname is None: + if name.name == "*": + error("import * is unsupproted") + else: + self.emit("local {name} = require(\"{module}\").{name}".format( + name=name.name, + module=module, + )) + else: + if name.name == "*": + error("import * is unsupproted") + else: + self.emit("local {name} = require(\"{module}\").{realname}".format( + name=name.asname, + module=module, + realname=name.name, + )) + + def visit_Index(self, node): + """Visit index""" + self.emit(self.visit_all(node.value, inline=True)) + + def visit_Lambda(self, node): + """Visit lambda""" + line = "function({arguments}) return" + + arguments = [arg.arg for arg in node.args.args] + + function_def = line.format(arguments=", ".join(arguments)) + + output = [] + output.append(function_def) + output.append(self.visit_all(node.body, inline=True)) + output.append("end") + + self.emit(" ".join(output)) + + def visit_List(self, node): + """Visit list""" + elements = [self.visit_all(item, inline=True) for item in node.elts] + line = "list {{{}}}".format(", ".join(elements)) + self.depend("list") + self.emit(line) + + def visit_GeneratorExp(self, node): + """Visit generator expression""" + self.emit("(function()") + self.emit("local result = list {}") + self.depend("list") + + ends_count = 0 + + for comp in node.generators: + line = "for {target} in {iterator} do" + values = { + "target": self.visit_all(comp.target, inline=True), + "iterator": self.visit_all(comp.iter, inline=True), + } + line = line.format(**values) + self.emit(line) + ends_count += 1 + + for if_ in comp.ifs: + line = "if {} then".format(self.visit_all(if_, inline=True)) + self.emit(line) + ends_count += 1 + + line = "result.append({})" + line = line.format(self.visit_all(node.elt, inline=True)) + self.emit(line) + + self.emit(" ".join(["end"] * ends_count)) + + self.emit("return result") + self.emit("end)()") + + def visit_ListComp(self, node): + """Visit list comprehension""" + self.emit("(function()") + self.emit("local result = list {}") + self.depend("list") + + ends_count = 0 + + for comp in node.generators: + line = "for {target} in {iterator} do" + values = { + "target": self.visit_all(comp.target, inline=True), + "iterator": self.visit_all(comp.iter, inline=True), + } + line = line.format(**values) + self.emit(line) + ends_count += 1 + + for if_ in comp.ifs: + line = "if {} then".format(self.visit_all(if_, inline=True)) + self.emit(line) + ends_count += 1 + + line = "result.append({})" + line = line.format(self.visit_all(node.elt, inline=True)) + self.emit(line) + + self.emit(" ".join(["end"] * ends_count)) + + self.emit("return result") + self.emit("end)()") + + def visit_Module(self, node): + """Visit module""" + self.visit_all(node.body) + self.output = self.output[0] + + def visit_Name(self, node): + """Visit name""" + self.emit(node.id) + + def visit_NameConstant(self, node): + """Visit name constant""" + self.emit(NameConstantDesc.NAME[node.value]) + + def visit_Num(self, node): + """Visit number""" + self.emit(str(node.n)) + + def visit_Pass(self, node): + """Visit pass""" + pass + + def visit_Return(self, node): + """Visit return""" + line = "return " + line += self.visit_all(node.value, inline=True) + self.emit(line) + + def visit_Starred(self, node): + """Visit starred object""" + value = self.visit_all(node.value, inline=True) + line = "unpack({})".format(value) + self.emit(line) + + def visit_Str(self, node): + """Visit str""" + value = node.s + if value.startswith(NodeVisitor.LUACODE): + value = value[len(NodeVisitor.LUACODE):] + self.emit(value) + elif self.context.last()["docstring"]: + self.emit('--[[ {} ]]'.format(node.s)) + else: + self.emit('"{}"'.format(node.s)) + + def visit_Subscript(self, node): + """Visit subscript""" + line = "{name}[{index}]" + values = { + "name": self.visit_all(node.value, inline=True), + "index": self.visit_all(node.slice, inline=True), + } + + self.emit(line.format(**values)) + + def visit_Tuple(self, node): + """Visit tuple""" + elements = [self.visit_all(item, inline=True) for item in node.elts] + self.emit(", ".join(elements)) + + def visit_UnaryOp(self, node): + """Visit unary operator""" + operation = UnaryOperationDesc.OPERATION[node.op.__class__] + value = self.visit_all(node.operand, inline=True) + + line = operation["format"] + #if operation["depend"]: + # self.depend(operation["depend"]) + values = { + "value": value, + "operation": operation["value"], + } + + self.emit(line.format(**values)) + + def visit_Raise(self, node): + """Visit raise""" + line = "error({})".format(self.visit_all(node.exc, inline=True)) + self.emit(line) + + def visit_Set(self, node): + """Visit set""" + values = [self.visit_all(value, True) for value in node.elts] + self.emit('{' + ', '.join(values) + '}') + + def visit_Try(self, node): + """Visit try""" + self.emit("xpcall(function()") + + self.visit_all(node.body) + + self.emit("end, function(err)") + + self.visit_all(node.handlers) + + self.emit("end)") + + def visit_ExceptHandler(self, node): + """Visit exception handler""" + if (node.type) != None: + if node.type.id == "Exception": + self.emit("local {} = err\n".format(node.name)) # The \n does messup the token generator, but makes cleaner code + self.emit("if err then") + else: + self.emit("if err:find('{}') then".format(node.type.id)) + + self.visit_all(node.body) + + if (node.type) != None: + self.emit("end") + + + + def visit_While(self, node): + """Visit while""" + test = self.visit_all(node.test, inline=True) + + self.emit("while {} do".format(test)) + + continue_label = LoopCounter.get_next() + self.context.push({ + "loop_label_name": continue_label, + }) + self.visit_all(node.body) + self.context.pop() + + self.emit("end") + + + def visit_SetComp(self, node): + """Visit set comprehension""" + self.emit("(function()") + self.emit("local result = {}") + ends_count = 0 + for comp in node.generators: + line = "for {target} in {iterator} do" + values = { + "target": self.visit_all(comp.target, inline=True), + "iterator": self.visit_all(comp.iter, inline=True), + } + line = line.format(**values) + self.emit(line) + ends_count += 1 + for if_ in comp.ifs: + line = "if {} then".format(self.visit_all(if_, inline=True)) + self.emit(line) + ends_count += 1 + line = "table.insert(result, {})" + line = line.format(self.visit_all(node.elt, inline=True)) + self.emit(line) + self.emit(" ".join(["end"] * ends_count)) + self.emit("return result") + self.emit("end)()") + + def visit_With(self, node): + """Visit with""" + self.emit("do") + + self.visit_all(node.body) + + body = self.output[-1] + lines = [] + for i in node.items: + line = "" + if i.optional_vars is not None: + line = "local {} = " + line = line.format(self.visit_all(i.optional_vars, + inline=True)) + line += self.visit_all(i.context_expr, inline=True) + lines.append(line) + + for line in lines: + body.insert(0, line) + + self.emit("end") + + def generic_visit(self, node): + """Unknown nodes handler""" + if node is None: + return + error("Unsupported feature: '{}'".format(node.__class__.__name__)) + + def visit_all(self, nodes, inline=False): + """Visit all nodes in the given list""" + + if not inline: + last_ctx = self.context.last() + last_ctx["locals"].push() + + visitor = NodeVisitor(context=self.context, config=self.config) + + if isinstance(nodes, list): + for node in nodes: + visitor.visit(node) + if not inline: + self.output.append(visitor.output) + else: + visitor.visit(nodes) + if not inline: + self.output.extend(visitor.output) + + if not inline: + last_ctx = self.context.last() + last_ctx["locals"].pop() + + if inline: + return " ".join(visitor.output) + + def emit(self, value): + """Add translated value to the output""" + self.output.append(value) + def depend(self, value): + if value != "": + dependencies.append(value) + +"""Header""" +HEADER = f"--// Generated by roblox-py v{VERSION} \\\\--\n" +PY_HEADER = f"## Generated by roblox-py v{VERSION} ##\n" + +"""Python to lua translator class""" +class Translator: + """Python to lua main class translator""" + def __init__(self, config=None, show_ast=False): + self.config = config if config is not None else Config() + self.show_ast = show_ast + + self.output = [] + + def translate(self, pycode, fn, isAPI = False, export = True, reqfile = False, useRequire = False): + """Translate python code to lua code""" + DEPEND = "\n\n--// REQUIREMENTS \\\\--\n" + + if not reqfile: + if isAPI: + py_ast_tree = ast.parse(pycode) + else: + try: + # code that uses ast + py_ast_tree = ast.parse(pycode) + except SyntaxError as err: + sys.stderr.write("\033[1;31m" + "syntax error: " + "\033[0m" + str(err) + "\n") + sys.exit(1) + + visitor = NodeVisitor(config=self.config) + + if self.show_ast: + print(ast.dump(py_ast_tree)) + + visitor.visit(py_ast_tree) + + self.output = visitor.output + + # Remove duplicates from dependencies (list) + global dependencies + dependencies = list(set(dependencies)) + + global exports + exports = list(set(exports)) + + if fn: + dependencies.append("fn") + if export and exports != []: + FOOTER = "\n\n--// EXPORTS \\\\--\n" + FOOTER += "if not script:IsA(\"BaseScript\") then\n\treturn {\n" + for export in exports: + FOOTER += f"\t\t[\"{export}\"] = {export},\n" + FOOTER += "\t}\nend" + else: + FOOTER = "" + + if reqfile: + dependencies = ["class", "dict", "list", "in", "fn", "safeadd"] + if not useRequire: + for depend in dependencies: + # set + + if depend == "list": + DEPEND += """\n\nfunction list(t) + local result = {} + + result._is_list = true + + result._data = {} + for _, v in ipairs(t) do + table.insert(result._data, v) + end + + local methods = {} + + methods.append = function(value) + table.insert(result._data, value) + end + + methods.extend = function(iterable) + for value in iterable do + table.insert(result._data, value) + end + end + + methods.insert = function(index, value) + table.insert(result._data, index, value) + end + + methods.remove = function(value) + for i, v in ipairs(result._data) do + if value == v then + table.remove(result._data, i) + break + end + end + end + + methods.pop = function(index) + index = index or #result._data + local value = result._data[index] + table.remove(result._data, index) + return value + end + + methods.clear = function() + result._data = {} + end + + methods.index = function(value, start, end_) + start = start or 1 + end_ = end_ or #result._data + + for i = start, end_, 1 do + if result._data[i] == value then + return i + end + end + + return nil + end + + methods.count = function(value) + local cnt = 0 + for _, v in ipairs(result._data) do + if v == value then + cnt = cnt + 1 + end + end + + return cnt + end + + methods.sort = function(key, reverse) + key = key or nil + reverse = reverse or false + + table.sort(result._data, function(a, b) + if reverse then + return a < b + end + + return a > b + end) + end + + methods.reverse = function() + local new_data = {} + for i = #result._data, 1, -1 do + table.insert(new_data, result._data[i]) + end + + result._data = new_data + end + + methods.copy = function() + return list(result._data) + end + + local iterator_index = nil + + setmetatable(result, { + __index = function(self, index) + if typeof(index) == "number" then + if index < 0 then + index = #result._data + index + end + return rawget(result._data, index + 1) + end + return methods[index] + end, + __newindex = function(self, index, value) + result._data[index] = value + end, + __call = function(self, _, idx) + if idx == nil and iterator_index ~= nil then + iterator_index = nil + end + + local v = nil + iterator_index, v = next(result._data, iterator_index) + + return v + end, + }) + + return result + end""" + elif depend == "dict": + DEPEND += """\n\nfunction dict(t) + local result = {} + + result._is_dict = true + + result._data = {} + for k, v in pairs(t) do + result._data[k] = v + end + + local methods = {} + + local key_index = nil + + methods.clear = function() + result._data = {} + end + + methods.copy = function() + return dict(result._data) + end + + methods.get = function(key, default) + default = default or nil + if result._data[key] == nil then + return default + end + + return result._data[key] + end + + methods.items = function() + return pairs(result._data) + end + + methods.keys = function() + return function(self, idx, _) + if idx == nil and key_index ~= nil then + key_index = nil + end + + key_index, _ = next(result._data, key_index) + return key_index + end + end + + methods.pop = function(key, default) + default = default or nil + if result._data[key] ~= nil then + local value = result._data[key] + result._data[key] = nil + return key, value + end + + return key, default + end + + methods.popitem = function() + local key, value = next(result._data) + if key ~= nil then + result._data[key] = nil + end + + return key, value + end + + methods.setdefault = function(key, default) + if result._data[key] == nil then + result._data[key] = default + end + + return result._data[key] + end + + methods.update = function(t) + assert(t._is_dict) + + for k, v in t.items() do + result._data[k] = v + end + end + + methods.values = function() + return function(self, idx, _) + if idx == nil and key_index ~= nil then + key_index = nil + end + + local key_index, value = next(result._data, key_index) + return value + end + end + + setmetatable(result, { + __index = function(self, index) + if result._data[index] ~= nil then + return result._data[index] + end + return methods[index] + end, + __newindex = function(self, index, value) + result._data[index] = value + end, + __call = function(self, _, idx) + if idx == nil and key_index ~= nil then + key_index = nil + end + + key_index, _ = next(result._data, key_index) + + return key_index + end, + }) + + return result + end""" + elif depend == "class": + DEPEND += """\n\nfunction class(class_init, bases) + bases = bases or {} + + local c = {} + + for _, base in ipairs(bases) do + for k, v in pairs(base) do + c[k] = v + end + end + + c._bases = bases + + c = class_init(c) + + local mt = getmetatable(c) or {} + mt.__call = function(_, ...) + local object = {} + + setmetatable(object, { + __index = function(tbl, idx) + local method = c[idx] + if typeof(method) == "function" then + return function(...) + return c[idx](object, ...) + end + end + + return method + end, + }) + + if typeof(object.__init__) == "function" then + object.__init__(...) + end + + return object + end + + setmetatable(c, mt) + + return c + end""" + elif depend == "in": + DEPEND += """\n\nfunction op_in(item, items) + if type(items) == "table" then + for v in items do + if v == item then + return true + end + end + elseif type(items) == "string" and type(item) == "string" then + return string.find(items, item, 1, true) ~= nil + end + + return false + end""" + elif depend == "fn": + DEPEND += """\n\nif game then + __name__ = if script:IsA("BaseScript") then "__main__" else script.Name + else + __name__ = nil + end + range = function(s, e) -- range() + local tb = {} + local a = 0 + local b = 0 + if not e then a=1 else a=s end + if not e then b=s else b=e end + for i = a, b do + tb[#tb+1] = i + end + return tb + end + len = function(x) return #x end -- len() + abs = math.abs -- abs() + str = tostring -- str() + int = tonumber -- int() + sum = function(tbl) --sum() + local total = 0 + for _, v in ipairs(tbl) do + total = total + v + end + return total + end + max = function(tbl) --max() + local maxValue = -math.huge + for _, v in ipairs(tbl) do + if v > maxValue then + maxValue = v + end + end + return maxValue + end + min = function(tbl) --min() + local minValue = math.huge + for _, v in ipairs(tbl) do + if v < minValue then + minValue = v + end + end + return minValue + end + reversed = function(seq) -- reversed() + local reversedSeq = {} + local length = #seq + for i = length, 1, -1 do + reversedSeq[length - i + 1] = seq[i] + end + return reversedSeq + end + split = function(str, sep) -- split + local substrings = {} + local pattern = string.format("([^%s]+)",sep or "%s") + for substring in string.gmatch(str, pattern) do + table.insert(substrings, substring) + end + return substrings + end + round = math.round -- round() + all = function (iter) -- all() + for i, v in iter do if not v then return false end end + + return true + end + any = function (iter) -- any() + for i, v in iter do + if v then return true end + end + return false + end + ord = string.byte -- ord + chr = string.char -- chr + callable = function(fun) -- callable() + if rawget(fun) ~= fun then warn("At the momement Roblox.py's function callable() does not fully support metatables.") end + return typeof(rawget(fun)) == "function" + end + float = tonumber -- float() + super = function() + error("roblox-pyc does not has a Lua implementation of the function `super`. Use `self` instead") + end + format = function(format, ...) -- format + local args = {...} + local num_args = select("#", ...) + + local formatted_string = string.gsub(format, "{(%d+)}", function(index) + index = tonumber(index) + if index >= 1 and index <= num_args then + return tostring(args[index]) + else + return "{" .. index .. "}" + end + end) + + return formatted_string + end + hex = function (value) -- hex + return string.format("%x", value) + end + id = function (obj) -- id + return print(tostring({obj}):gsub("table: ", ""):split(" ")[1]) + end + map = function (func, ...) --map + local args = {...} + local result = {} + local num_args = select("#", ...) + + local shortest_length = math.huge + for i = 1, num_args do + local arg = args[i] + local arg_length = #arg + if arg_length < shortest_length then + shortest_length = arg_length + end + end + + for i = 1, shortest_length do + local mapped_args = {} + for j = 1, num_args do + local arg = args[j] + table.insert(mapped_args, arg[i]) + end + table.insert(result, func(unpack(mapped_args))) + end + + return result + end + bool = function(x) -- bool + if x == false or x == nil or x == 0 then + return false + end + + if typeof(x) == "table" then + if x._is_list or x._is_dict then + return next(x._data) ~= nil + end + end + + return true + end + divmod = function(a, b) -- divmod + local res = { math.floor(a / b), math.fmod(a, b) } + return unpack(res) + end + slice = function (seq, start, stop, step) + local sliced = {} + local len = #seq + start = start or 1 + stop = stop or len + step = step or 1 + if start < 0 then + start = len + start + 1 + end + if stop < 0 then + stop = len + stop + 1 + end + for i = start, stop - 1, step do + table.insert(sliced, seq[i]) + end + return sliced + end + anext = function (iterator) -- anext + local status, value = pcall(iterator) + if status then + return value + end + end + ascii = function (obj) -- ascii + return string.format("%q", tostring(obj)) + end + dir = function (obj) -- dir + local result = {} + for key, _ in pairs(obj) do + table.insert(result, key) + end + return result + end + getattr = function (obj, name, default) -- getattr + local value = obj[name] + if value == nil then + return default + end + return value + end + globals = function () -- globals + return _G + end + hasattr = function (obj, name) --hasattr + return obj[name] ~= nil + end + isinstance = function (obj, class) -- isinstance + return type(obj) == class + end + issubclass = function (cls, classinfo) -- issubclass + local mt = getmetatable(cls) + while mt do + if mt.__index == classinfo then + return true + end + mt = getmetatable(mt.__index) + end + return false + end + iter = function (obj) -- iter + if type(obj) == "table" and obj.__iter__ ~= nil then + return obj.__iter__ + end + return nil + end + locals = function () -- locals + return _G + end + oct = function (num) --oct + return string.format("%o", num) + end + pow = function (base, exponent, modulo) --pow + if modulo ~= nil then + return math.pow(base, exponent) % modulo + else + return base ^ exponent + end + end + eval = function (expr, env) + return loadstring(expr)() + end + exec = loadstring + filter = function (predicate, iterable) + local result = {} + for _, value in ipairs(iterable) do + if predicate(value) then + table.insert(result, value) + end + end + return result + end + frozenset = function (...) + local elements = {...} + local frozenSet = {} + for _, element in ipairs(elements) do + frozenSet[element] = true + end + return frozenSet + end + aiter = function (iterable) -- aiter + return pairs(iterable) + end + bin = function(num: number) + local bits = {} + repeat + table.insert(bits, 1, num % 2) + num = math.floor(num / 2) + until num == 0 + return "0b" .. table.concat(bits) + end + complex = function (real, imag) -- complex + return { real = real, imag = imag } + end + deltaattr = function (object, attribute) -- delattr + object[attribute] = nil + end + enumerate = function (iterable) -- enumerate + local i = 0 + return function() + i = i + 1 + local value = iterable[i] + if value ~= nil then + return i, value + end + end + end + bytearray = function (arg) -- bytearray + if type(arg) == "string" then + local bytes = {} + for i = 1, #arg do + table.insert(bytes, string.byte(arg, i)) + end + return bytes + elseif type(arg) == "number" then + local bytes = {} + while arg > 0 do + table.insert(bytes, 1, arg % 256) + arg = math.floor(arg / 256) + end + return bytes + elseif type(arg) == "table" then + return arg -- Assuming it's already a bytearray table + else + error("Invalid argument type for bytearray()") + end + end + bytes = function (arg) -- bytes + if type(arg) == "string" then + local bytes = {} + for i = 1, #arg do + table.insert(bytes, string.byte(arg, i)) + end + return bytes + elseif type(arg) == "table" then + return arg -- Assuming it's already a bytes table + else + error("Invalid argument type for bytes()") + end + end + compile = loadstring + help = function (object) -- help + print("Help for object:", object) + print("Type:", type(object)) + print("Learn more in the official roblox documentation!") + end + memoryview = function (object) -- memoryview + if type(object) == "table" then + local buffer = table.concat(object) + return { buffer = buffer, itemsize = 1 } + else + error("Invalid argument type for memoryview()") + end + end + repr = function (object) -- repr + return tostring(object) + end + sorted = function (iterable, cmp, key, reverse) -- sorted + local sortedTable = {} + for key, value in pairs(iterable) do + table.insert(sortedTable, { key = key, value = value }) + end + table.sort(sortedTable, function(a, b) + -- Compare logic based on cmp, key, reverse parameters + return a.key < b.key + end) + local i = 0 + return function() + i = i + 1 + local entry = sortedTable[i] + if entry then + return entry.key, entry.value + end + end + end + vars = function (object) -- vars + local attributes = {} + for key, value in pairs(object) do + attributes[key] = value + end + return attributes + end""" + elif depend == "safeadd": + DEPEND += """\n\nfunction safeadd(a, b) + if type(a) == "number" and type(b) == "number" then + return a + b + elseif type(a) == "string" and type(b) == "string" then + return a .. b + else + error(`Attempt to add a {type(a)} and a {type(b)}`) + end + end""" + else: + error("Auto-generated dependency unhandled '{}', please report this issue on Discord or Github".format(depend)) + + if not reqfile: + DEPEND += "\n\n----- CODE START -----\n" + else: + DEPEND += "\n\nreturn env" + return DEPEND + + CODE = self.to_code() + libs = ["class", "dict", "list", "op_in", "safeadd", "__name__", "range", "len", "abs", "str", "int", "sum", "max", "min", "reversed", "split", "round", "all", "any", "ord", "chr", "callable", "float", "super", "format", "hex", "id", "map", "bool", "divmod", "slice", "anext", "ascii", "dir", "getattr", "globals", "hasattr", "isinstance", "issubclass", "iter", "locals", "oct", "pow", "eval", "exec", "filter", "frozenset", "aiter", "bin", "complex", "deltaattr", "enumerate", "bytearray", "bytes", "compile", "help", "memoryview", "repr", "sorted", "vars"] + + if useRequire: + DEPEND = """\n\n--// Imports \\\\-- +py = _G.rbxpy or require(game.ReplicatedStorage.rbxpy) + +""" + for i in libs: + if i in CODE: + DEPEND += f"{i} = py.{i}" + + DEPEND += "\n\n----- CODE START -----\n" + + + return HEADER + DEPEND + CODE + FOOTER + + def to_code(self, code=None, indent=0): + """Create a lua code from the compiler output""" + code = code if code is not None else self.output + + def add_indentation(line): + """Add indentation to the given line""" + indentation_width = 4 + indentation_space = " " + + indent_copy = max(indent, 0) + + return indentation_space * indentation_width * indent_copy + line + + lines = [] + for line in code: + if isinstance(line, str): + lines.append(add_indentation(line)) + elif isinstance(line, list): + sub_code = self.to_code(line, indent + 1) + lines.append(sub_code) + + return "\n".join(lines) + + @staticmethod + def get_luainit(): # Return STDlib + return """""" + +#class PyGenerator: + +#### INTERFACE #### +def warn(msg): + sys.stderr.write("\033[1;33m" + "warning: " + "\033[0m" + msg) +def info(msg): + sys.stderr.write("\033[1;32m" + "info: " + "\033[0m" + msg) +def error(msg): + sys.stderr.write("\033[1;31m" + "error: " + "\033[0m" + msg + "\n") + sys.exit() + +def usage(): + print("\n"+f"""usage: \033[1;33mrbxpy\033[0m [file] [options] > [gen] +\033[1mOptions:\033[0m +{TAB}\033[1m-v\033[0m show version information +{TAB}\033[1m-vd\033[0m show version number only" +{TAB}\033[1m-ast\033[0m show python ast tree before code +{TAB}\033[1m-f\033[0m include standard python functions in generated code +{TAB}\033[1m-fn\033[0m do not include standard python functions in generated code +{TAB}\033[1m-u\033[0m open this""") + sys.exit() + +def version(): + print("\033[1;34m" + "copyright:" + "\033[0m" + " roblox-py " + "\033[1m" + VERSION + "\033[0m" + " licensed under the GNU Affero General Public License by " + "\033[1m" + "@AsynchronousAI" + "\033[0m") + sys.exit(0) + +def provideerr(err): + global proverr + proverr = err + +"""The main entry point to the translator""" +def main(): + """Entry point function to the translator""" + + # Enable support for ANSI escape sequences + if os.name == "nt": + os.system("cmd /c \"setx ENABLE_VIRTUAL_TERMINAL_PROCESSING 1\"") + + args = sys.argv[1:] + ast = False + input_filename = "NONE" + out = "NONE" + type = 1 # 1: py->lua, 2: lua->py + includeSTD = False + export = True + skip = False + reqfile = None + useRequire = False + + for arg in args: + if skip: + skip = False + continue + + if arg == "-v": + version() + elif arg == "-vd": + print(VERSION) + sys.exit() + elif arg == "-u": + usage() + elif arg == "-f": + includeSTD = True + elif arg == "-s": + reqfile = True + elif arg == "-r": + useRequire = True + elif arg == "-fn": + includeSTD = False + elif arg == "-ne": + export = False + elif arg == "-ast": + ast = True + elif arg == "-py": + type = 1 + elif arg == "-o": + out = args[args.index(arg)+1] + skip = True + elif arg == "-lua": + type = 2 + else: + if input_filename != "NONE": + error("Unexpected argument: '{}'".format(arg)) + input_filename = arg + + if type == 1: + if (input_filename == "NONE") and not reqfile: + usage() + if (not Path(input_filename).is_file()) and not reqfile: + error( + "The given filename ('{}') is not a file.".format(input_filename)) + + if not reqfile: + content = None + with open(input_filename, "r") as file: + content = file.read() + + if not content: + error("The input file is empty.") + + translator = Translator(Config(".pyluaconf.yaml"), + show_ast=ast) + if reqfile: + reqcode = translator.translate("", True, False, False, True) + if out != "NONE": + with open(out, "w") as file: + file.write(reqcode) + else: + print(reqcode) + sys.exit(0) + else: + lua_code = translator.translate(content, includeSTD, False, export, False, useRequire) + + if not ast: + if out != "NONE": + with open(out, "w") as file: + file.write(lua_code) + else: + print(lua_code) + else: + command = "luac -l "+input_filename + + try: + res = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + sys.exit(1) + + res = (res.decode("utf-8")) + + # Parse + commands = {} + + lines = res.split("\n") + lines.pop(0) + lines.pop(0) + lines.pop(0) + for line in lines: + data = line.split("\t") + if len(data) < 4: + continue + num, cmd, args = data[1], data[3], data[4] + if len(data) > 5: + data = data[5] + else: + data = "NONE" + + commands[num] = {"cmd": cmd, "args": args, "data": data} + res = "\n".join(lines) + + print(commands) + + # If luac.out is found then remove it + if Path("luac.out").is_file(): + os.remove("luac.out") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/test/c/test.c b/test/c/test.c deleted file mode 100644 index 5d6e495..0000000 --- a/test/c/test.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -int factorial(int n) { - if (n == 0 || n == 1) { - return 1; - } else { - return n * factorial(n - 1); - } -} - -int main() { - int num = 5; - int result = factorial(num); - - printf("The factorial of %d is %d\n", num, result); - - return 0; -} - diff --git a/test/cpp/test.cpp b/test/cpp/test.cpp deleted file mode 100644 index 74cad96..0000000 --- a/test/cpp/test.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -int factorial(int n) { - if (n == 0 || n == 1) { - return 1; - } else { - return n * factorial(n - 1); - } -} - -int main() { - int num = 5; - int result = factorial(num); - - std::cout << "The factorial of " << num << " is " << result << std::endl; - - return 0; -} diff --git a/test/json.json b/test/json.json deleted file mode 100644 index 7196507..0000000 --- a/test/json.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "example", - "version": "1.0.0", - "stuff": { - "stuff numero uno": "1", - "stuff numero dos": "2", - "stuff numero tres": "]]3" - } -} diff --git a/test/json.lua b/test/json.lua deleted file mode 100644 index 662abeb..0000000 --- a/test/json.lua +++ /dev/null @@ -1,2 +0,0 @@ ---/ Compiled using roblox-pyc | JSON compiler \-- -return {Contents = {["name"] = "example", ["version"] = "1.0.0", ["stuff"] = {["stuff numero uno"] = "1", ["stuff numero dos"] = "2", ["stuff numero tres"] = "]]3"}}, Type = 'json', Extension = 'json', SetSource = function(self, input) self.Contents = input end} \ No newline at end of file diff --git a/test/lunar/count.lua b/test/lunar/count.lua deleted file mode 100644 index 96ca6f5..0000000 --- a/test/lunar/count.lua +++ /dev/null @@ -1,43 +0,0 @@ -local count -count = function(current) - if current ~= nil then - if typeof(current == "number") then - if current > 0 then - print(current) - return count(current - 1) - else - if current == 0 then - return print(current) - else - print(current) - return count(current + 1) - end - end - elseif typeof(current == "table") then - if current.length > 0 then - print(current) - return count(current.slice(0, current.length - 1)) - else - return print(current) - end - else - print(current) - return count(current + 1) - end - else - return print("Next time, give me a number!") - end -end -count(0) -count(5) -count() -count(-1) -count(0) -count(1) -count(2.0) -count("hi") -return count({ - 1, - 2, - 3 -}) diff --git a/test/lunar/count.moon b/test/lunar/count.moon deleted file mode 100644 index ed31823..0000000 --- a/test/lunar/count.moon +++ /dev/null @@ -1,33 +0,0 @@ -count = (current)-> - if current != nil - if typeof current == "number" - if current > 0 - print current - count current-1 - else if current == 0 - print current - else - print current - count current+1 - elseif typeof current == "table" - if current.length > 0 - print current - count current.slice(0,current.length-1) - else - print current - else - print current - count current+1 - - else - print "Next time, give me a number!" - -count(0) -count 5 -count! -count -1 -count 0 -count 1 -count 2.0 -count "hi" -count {1,2,3} \ No newline at end of file diff --git a/test/lunar/customlib.lua b/test/lunar/customlib.lua deleted file mode 100644 index 22647ac..0000000 --- a/test/lunar/customlib.lua +++ /dev/null @@ -1,11 +0,0 @@ -local checker = type("string", "number", "boolean", "nil", "table", "function") -assert(checker("hello", 1, true, nil, { })) -assert(checker(1, 2, 3, 4, 5, 6)) -print(table.shuffle({ - 1, - 2, - 3, - 4, - 5 -})) -return nil diff --git a/test/lunar/customlib.moon b/test/lunar/customlib.moon deleted file mode 100644 index b69e292..0000000 --- a/test/lunar/customlib.moon +++ /dev/null @@ -1,13 +0,0 @@ --- Lunar has an extended table library, which is a superset of the standard Lua table library, use table. --- Lunar also has an extended type system, which is a superset of the standard Lua type system, use type. - --- TYPECHECKER AND EXTENDED TABLE LIBRARY ARE NOW DECREAPTED!!!!!!!!!!!!!!!!!! --- ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ -checker = type("string", "number", "boolean", "nil", "table", "function") - -assert(checker("hello", 1, true, nil, {})) -- Matches classes so no errors -assert(checker(1, 2, 3, 4, 5, 6)) -- Doesnt match classes so errors - -print table.shuffle({1, 2, 3, 4, 5}) - -nil -- last line is return value diff --git a/test/python/API.lua b/test/python/API.lua deleted file mode 100644 index 604f0fe..0000000 --- a/test/python/API.lua +++ /dev/null @@ -1,47 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local list = builtin.list -local id = builtin.id -local int = builtin.int -local print = builtin.print -local Spawn = builtin.Spawn -local Workspace = builtin.Workspace -local operator_in = builtin.operator_in -local min = builtin.min -local game = builtin.game - ------------------------------------------------------------------------------ -local examplelibrary = import("example") -local newSignal = import("signal", "new") -local ValidPlayers = list {"builderman"} -local function onTouch(touch) - print("Spawn has been touched by", touch.Name) -end -onTouch = py.Workspace.Spawn.Touched(onTouch) -local function onPlrAdd(plr) - if (operator_in(plr.Name, ValidPlayers)) then - print("Admin", plr.Name, "has joined the game!!") - end -end -onPlrAdd = py.Players.PlayerAdded(onPlrAdd) -examplelibrary() -local function onSignal() - print("Signal received!") -end -onSignal = newSignal(onSignal) -onSignal.Fire() - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/API.py b/test/python/API.py deleted file mode 100644 index 290fdfb..0000000 --- a/test/python/API.py +++ /dev/null @@ -1,23 +0,0 @@ -import example as examplelibrary -from signal import new as newSignal - -ValidPlayers = [ - "builderman" -] - -@py.Workspace.Spawn.Touched -def onTouch(touch): - print("Spawn has been touched by", touch.Name) - -@py.Players.PlayerAdded -def onPlrAdd(plr): - if plr.Name in ValidPlayers: - # The player is in our admin list, print admin joined - print("Admin", plr.Name, "has joined the game!!") - -examplelibrary() # -> Example Library! -@newSignal -def onSignal(): - print("Signal received!") - -onSignal.Fire() # -> Signal received! \ No newline at end of file diff --git a/test/python/ann.lua b/test/python/ann.lua deleted file mode 100644 index 2515b1e..0000000 --- a/test/python/ann.lua +++ /dev/null @@ -1,21 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - - ------------------------------------------------------------------------------ -local x = 10 -local y = 20 - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/ann.py b/test/python/ann.py deleted file mode 100644 index 4db8e71..0000000 --- a/test/python/ann.py +++ /dev/null @@ -1,3 +0,0 @@ -x: int = 10 -y: int = 20 - diff --git a/test/python/asyncdef.lua b/test/python/asyncdef.lua deleted file mode 100644 index d15cdcc..0000000 --- a/test/python/asyncdef.lua +++ /dev/null @@ -1,25 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local asynchronousfunction = builtin.asynchronousfunction -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local hello = asynchronousfunction(function() - print("Hello, world!") -end) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/asyncdef.py b/test/python/asyncdef.py deleted file mode 100644 index 3d4533f..0000000 --- a/test/python/asyncdef.py +++ /dev/null @@ -1,3 +0,0 @@ -async def hello(): - print("Hello, world!") - diff --git a/test/python/asyncwith.lua b/test/python/asyncwith.lua deleted file mode 100644 index 65dcb83..0000000 --- a/test/python/asyncwith.lua +++ /dev/null @@ -1,31 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local asynchronousfunction = builtin.asynchronousfunction -local open = builtin.open -local coroutine = builtin.coroutine -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local async_with = asynchronousfunction(function() - do - local f = open("test.txt") - local contents = coroutine.yield(f.read()) - print(contents) - end -end) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/asyncwith.py b/test/python/asyncwith.py deleted file mode 100644 index b5f3c80..0000000 --- a/test/python/asyncwith.py +++ /dev/null @@ -1,4 +0,0 @@ -async def async_with(): - with open('test.txt') as f: - contents = await f.read() - print(contents) \ No newline at end of file diff --git a/test/python/bytes.lua b/test/python/bytes.lua deleted file mode 100644 index ad4349f..0000000 --- a/test/python/bytes.lua +++ /dev/null @@ -1,23 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local byte = 'Hello World' -print(byte) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/bytes.py b/test/python/bytes.py deleted file mode 100644 index 4d9f2fb..0000000 --- a/test/python/bytes.py +++ /dev/null @@ -1,2 +0,0 @@ -byte = b"Hello World" -print(byte) \ No newline at end of file diff --git a/test/python/class.lua b/test/python/class.lua deleted file mode 100644 index 56aee78..0000000 --- a/test/python/class.lua +++ /dev/null @@ -1,48 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local class = builtin.class -local int = builtin.int -local print = builtin.print -local Game = builtin.Game - ------------------------------------------------------------------------------ -local Example = class(function(Example) - function Example.__init__(self, name) - self.name = name - end - function Example.print_name(self) - print(self.name) - end - function Example.sethobby(self, hobby) - self.hobby = hobby - end - function Example.printhobby(self) - print(self.hobby) - end - function Example.setage(self, age) - self.age = age - end - function Example.printage(self) - print(self.age) - end - return Example -end, {}) -local new = Example("John") -new.print_name() -new.sethobby("Roblox Game Development") -new.printhobby() - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/class.py b/test/python/class.py deleted file mode 100644 index 0591a15..0000000 --- a/test/python/class.py +++ /dev/null @@ -1,24 +0,0 @@ -class Example: - def __init__(self, name): - self.name = name - - def print_name(self): - print(self.name) - - def sethobby(self, hobby): - self.hobby = hobby - - def printhobby(self): - print(self.hobby) - - def setage(self, age): - self.age = age - - def printage(self): - print(self.age) - - -new = Example("John") -new.print_name() -new.sethobby("Roblox Game Development") -new.printhobby() \ No newline at end of file diff --git a/test/python/continue.lua b/test/python/continue.lua deleted file mode 100644 index 4efd820..0000000 --- a/test/python/continue.lua +++ /dev/null @@ -1,25 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local range = builtin.range - ------------------------------------------------------------------------------ -for i in range(10) do - if (i == 5) then - continue - end -end - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/continue.py b/test/python/continue.py deleted file mode 100644 index 48f5359..0000000 --- a/test/python/continue.py +++ /dev/null @@ -1,6 +0,0 @@ -# continue tests - -for i in range(10): - if i == 5: - continue - diff --git a/test/python/dict.lua b/test/python/dict.lua deleted file mode 100644 index 575928c..0000000 --- a/test/python/dict.lua +++ /dev/null @@ -1,30 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local dict = builtin.dict -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local newdict = dict {} -newdict["one"] = 1 -newdict["two"] = 2 -newdict["three"] = 3 -newdict["four"] = 4 -for key in newdict do - print(key, newdict[key]) -end - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/dict.py b/test/python/dict.py deleted file mode 100644 index a65ebf2..0000000 --- a/test/python/dict.py +++ /dev/null @@ -1,8 +0,0 @@ -newdict = {} -newdict['one'] = 1 -newdict['two'] = 2 -newdict['three'] = 3 -newdict['four'] = 4 - -for key in newdict: - print(key, newdict[key]) \ No newline at end of file diff --git a/test/python/doublestar.lua b/test/python/doublestar.lua deleted file mode 100644 index 5fedad7..0000000 --- a/test/python/doublestar.lua +++ /dev/null @@ -1,23 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local dict = builtin.dict - ------------------------------------------------------------------------------ -local x = dict {["a"] = "b", ["c"] = "d"} -local a = "Hello, World!" -a.b() - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/doublestar.py b/test/python/doublestar.py deleted file mode 100644 index 9ab8cf4..0000000 --- a/test/python/doublestar.py +++ /dev/null @@ -1,9 +0,0 @@ -# Use ** in this python script - -# Path: test/python/doublestar.py - -x = {"a": "b", "c": "d"} -a = "Hello, World!" -a.b(**x) - -# This is an imaginary API, but it's just to show that the compiler works \ No newline at end of file diff --git a/test/python/formatusing%.lua b/test/python/formatusing%.lua deleted file mode 100644 index c8d8ac4..0000000 --- a/test/python/formatusing%.lua +++ /dev/null @@ -1,25 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local format = builtin.format -local formatmod = builtin.formatmod -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local text = (formatmod("%s is my name", "John")) -print(text) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/formatusing%.py b/test/python/formatusing%.py deleted file mode 100644 index cf8930f..0000000 --- a/test/python/formatusing%.py +++ /dev/null @@ -1,3 +0,0 @@ -text = "%s is my name" % "John" - -print(text) \ No newline at end of file diff --git a/test/python/helloworld.lua b/test/python/helloworld.lua deleted file mode 100644 index 802ec1a..0000000 --- a/test/python/helloworld.lua +++ /dev/null @@ -1,22 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -print("Hello World!") - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/helloworld.py b/test/python/helloworld.py deleted file mode 100644 index 1dc45ac..0000000 --- a/test/python/helloworld.py +++ /dev/null @@ -1 +0,0 @@ -print("Hello World!") \ No newline at end of file diff --git a/test/python/import.lua b/test/python/import.lua deleted file mode 100644 index 78eca94..0000000 --- a/test/python/import.lua +++ /dev/null @@ -1,26 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - - ------------------------------------------------------------------------------ -local examplelib = import("examplelib") -local submodule = import("examplelib.submodule") -local mysubsubmodule = import("examplelib.submodule.subsubmodule") -local submodule = import("examplefromlib", "submodule") -local mysubsubmodule = import("examplefromlib.submodule", "mysubsubmodule") -local mysubmodule2 = import("examplefromlib", "submodule") -local mysubsubmodule3 = import("examplefromlib.submodule", "subsubmodule") - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/import.py b/test/python/import.py deleted file mode 100644 index ae129f6..0000000 --- a/test/python/import.py +++ /dev/null @@ -1,8 +0,0 @@ -import examplelib -import examplelib.submodule -import examplelib.submodule.subsubmodule as mysubsubmodule -from examplefromlib import submodule -from examplefromlib.submodule import mysubsubmodule -from examplefromlib import submodule as mysubmodule2 -from examplefromlib.submodule import subsubmodule as mysubsubmodule3 - diff --git a/test/python/importall.lua b/test/python/importall.lua deleted file mode 100644 index 759d3b6..0000000 --- a/test/python/importall.lua +++ /dev/null @@ -1,22 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - - ------------------------------------------------------------------------------ -local newspring = import("spring", "new") -local b = import("a") -local newSpring = newspring() - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/importall.py b/test/python/importall.py deleted file mode 100644 index b28b024..0000000 --- a/test/python/importall.py +++ /dev/null @@ -1,4 +0,0 @@ -from spring import new as newspring -import a as b - -newSpring = newspring() diff --git a/test/python/in.lua b/test/python/in.lua deleted file mode 100644 index 1091c91..0000000 --- a/test/python/in.lua +++ /dev/null @@ -1,28 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local dict = builtin.dict -local table = builtin.table -local operator_in = builtin.operator_in -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local table = dict {["a"] = "b", ["c"] = "d"} -if (operator_in("a", table)) then - print("a is present in table") -end - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/in.py b/test/python/in.py deleted file mode 100644 index e9c7434..0000000 --- a/test/python/in.py +++ /dev/null @@ -1,4 +0,0 @@ -table = {"a": "b", "c": "d"} - -if "a" in table: - print("a is present in table") \ No newline at end of file diff --git a/test/python/lambda.lua b/test/python/lambda.lua deleted file mode 100644 index e4ba9b8..0000000 --- a/test/python/lambda.lua +++ /dev/null @@ -1,25 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local safeadd = builtin.safeadd -local bit32 = builtin.bit32 -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local x = function(a) return (bit32.bxor((bit32.bxor((safeadd(a, 10)), 2)), a)) end -print(x(5)) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/lambda.py b/test/python/lambda.py deleted file mode 100644 index 4b65f93..0000000 --- a/test/python/lambda.py +++ /dev/null @@ -1,2 +0,0 @@ -x = lambda a : a + 10^2^a -print(x(5)) \ No newline at end of file diff --git a/test/python/list.lua b/test/python/list.lua deleted file mode 100644 index 88918d2..0000000 --- a/test/python/list.lua +++ /dev/null @@ -1,33 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local list = builtin.list -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local newlist = list {1, 2, 3, 4, 5} -newlist.append(6) -newlist.append(7) -newlist.append(8) -for item in newlist do - print(item) -end -print(newlist[0]) -print(newlist[1]) -newlist.sort() -newlist.reverse() - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/list.py b/test/python/list.py deleted file mode 100644 index 9df2661..0000000 --- a/test/python/list.py +++ /dev/null @@ -1,13 +0,0 @@ -newlist = [1, 2, 3, 4, 5] -newlist.append(6) -newlist.append(7) -newlist.append(8) - -for item in newlist: - print(item) - -print(newlist[0]) -print(newlist[1]) - -newlist.sort() -newlist.reverse() \ No newline at end of file diff --git a/test/python/luaxpy.lua b/test/python/luaxpy.lua deleted file mode 100644 index 2a1aec8..0000000 --- a/test/python/luaxpy.lua +++ /dev/null @@ -1,26 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local python = builtin.python -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -print("This is from python!") - -print("This is from lua!") - - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/luaxpy.py b/test/python/luaxpy.py deleted file mode 100644 index f81e31e..0000000 --- a/test/python/luaxpy.py +++ /dev/null @@ -1,4 +0,0 @@ -print("This is from python!") -"""[[lua]] -print("This is from lua!") -""" \ No newline at end of file diff --git a/test/python/match.lua b/test/python/match.lua deleted file mode 100644 index ab104be..0000000 --- a/test/python/match.lua +++ /dev/null @@ -1,34 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local match = builtin.match -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local x = "10" -match(x, { -[10] = function() - print("x is 10") -end, -[20] = function() - print("x is 20") -end, -["default"] = function() - print("x is not 10 or 20") -end, -}) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/match.py b/test/python/match.py deleted file mode 100644 index 80970c4..0000000 --- a/test/python/match.py +++ /dev/null @@ -1,11 +0,0 @@ -x = "10" - -match x: - case "10": - print("x is 10") - case "20": - print("x is 20") - case _: - print("x is not 10 or 20") - - diff --git a/test/python/matrix.lua b/test/python/matrix.lua deleted file mode 100644 index 058f81c..0000000 --- a/test/python/matrix.lua +++ /dev/null @@ -1,34 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local list = builtin.list -local range = builtin.range -local len = builtin.len -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local X = list {list {12, 7}, list {4, 5}, list {3, 8}} -local result = list {list {0, 0, 0}, list {0, 0, 0}} -for i in range(len(X)) do - for j in range(len(X[0])) do - result[j][i] = X[i][j] - end -end -for r in result do - print(r) -end - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/matrix.py b/test/python/matrix.py deleted file mode 100644 index 8d1ae9c..0000000 --- a/test/python/matrix.py +++ /dev/null @@ -1,14 +0,0 @@ - -X = [[12,7], - [4 ,5], - [3 ,8]] - -result = [[0,0,0], - [0,0,0]] - -for i in range(len(X)): - for j in range(len(X[0])): - result[j][i] = X[i][j] - -for r in result: - print(r) diff --git a/test/python/memoryaddress.lua b/test/python/memoryaddress.lua deleted file mode 100644 index 33f6f0b..0000000 --- a/test/python/memoryaddress.lua +++ /dev/null @@ -1,25 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local id = builtin.id -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local item = "Hello!" -local location = id(item) -print(location) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/memoryaddress.py b/test/python/memoryaddress.py deleted file mode 100644 index c350633..0000000 --- a/test/python/memoryaddress.py +++ /dev/null @@ -1,4 +0,0 @@ -item = "Hello!" -location = id(item) - -print(location) \ No newline at end of file diff --git a/test/python/multiassign.lua b/test/python/multiassign.lua deleted file mode 100644 index c33a0df..0000000 --- a/test/python/multiassign.lua +++ /dev/null @@ -1,23 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local a, b, c = 1, 2, 3 -print(a, b, c) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/multiassign.py b/test/python/multiassign.py deleted file mode 100644 index 26c8937..0000000 --- a/test/python/multiassign.py +++ /dev/null @@ -1,2 +0,0 @@ -a,b,c = 1,2,3 -print(a,b,c) \ No newline at end of file diff --git a/test/python/slice.lua b/test/python/slice.lua deleted file mode 100644 index 2699717..0000000 --- a/test/python/slice.lua +++ /dev/null @@ -1,26 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local str = builtin.str -local string = builtin.string -local int = builtin.int -local slice = builtin.slice -local print = builtin.print - ------------------------------------------------------------------------------ -local string = "Hello World" -print(slice(string, 0, 5)) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/slice.py b/test/python/slice.py deleted file mode 100644 index 6f732ca..0000000 --- a/test/python/slice.py +++ /dev/null @@ -1,3 +0,0 @@ -string = "Hello World" -#print(string[0:5]) # Not enabled -print(slice(string, 0, 5)) \ No newline at end of file diff --git a/test/python/staticmethod.lua b/test/python/staticmethod.lua deleted file mode 100644 index 55ede76..0000000 --- a/test/python/staticmethod.lua +++ /dev/null @@ -1,36 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local int = builtin.int -local format = builtin.format -local exec = builtin.exec -local formatmod = builtin.formatmod -local print = builtin.print -local staticmethod = builtin.staticmethod -local class = builtin.class - ------------------------------------------------------------------------------ -local function foo(x) - print((formatmod("executing foo(%s)", x))) -end -foo = staticmethod(foo) -local A = class(function(A) - A.foo = foo - return A -end, {}) -local a = A() -a.foo("hi") - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/staticmethod.py b/test/python/staticmethod.py deleted file mode 100644 index b62d553..0000000 --- a/test/python/staticmethod.py +++ /dev/null @@ -1,9 +0,0 @@ -@staticmethod -def foo(x): - print("executing foo(%s)" % (x)) - -class A: - foo = foo - -a = A() -a.foo('hi') \ No newline at end of file diff --git a/test/python/string.lua b/test/python/string.lua deleted file mode 100644 index 51b0bd3..0000000 --- a/test/python/string.lua +++ /dev/null @@ -1,26 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local str = builtin.str -local string = builtin.string -local safeadd = builtin.safeadd -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local newstring = "Hello World" -print((safeadd(newstring, "Hi"))) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/string.py b/test/python/string.py deleted file mode 100644 index a149800..0000000 --- a/test/python/string.py +++ /dev/null @@ -1,2 +0,0 @@ -newstring = 'Hello World' -print(newstring+"Hi") \ No newline at end of file diff --git a/test/python/try.lua b/test/python/try.lua deleted file mode 100644 index c5e9fb6..0000000 --- a/test/python/try.lua +++ /dev/null @@ -1,25 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local all = builtin.all -local pcall = builtin.pcall -local error = builtin.error - ------------------------------------------------------------------------------ -local success, result = pcall(function() - error("Some error") -end) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/try.py b/test/python/try.py deleted file mode 100644 index 8274b43..0000000 --- a/test/python/try.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - raise "Some error" -finally: - print("This is from finally") \ No newline at end of file diff --git a/test/python/typehints.lua b/test/python/typehints.lua deleted file mode 100644 index ab58144..0000000 --- a/test/python/typehints.lua +++ /dev/null @@ -1,29 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local sum = builtin.sum -local safeadd = builtin.safeadd -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -local function sum_numbers(a, b) - return (safeadd(a, b)) -end -print(sum_numbers(10, 5)) -print(sum_numbers(10.3, 5)) -print(sum_numbers("Bob", "Mark")) - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/typehints.py b/test/python/typehints.py deleted file mode 100644 index 95f36ac..0000000 --- a/test/python/typehints.py +++ /dev/null @@ -1,9 +0,0 @@ -# TODO: Add compiler support for type hints, in functions and async functions. - - -def sum_numbers(a: int, b: int) -> int: - return a + b - -print(sum_numbers(10, 5)) -print(sum_numbers(10.3, 5)) -print(sum_numbers('Bob', 'Mark')) \ No newline at end of file diff --git a/test/python/with.lua b/test/python/with.lua deleted file mode 100644 index 9f38e42..0000000 --- a/test/python/with.lua +++ /dev/null @@ -1,26 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local id = builtin.id -local int = builtin.int -local print = builtin.print - ------------------------------------------------------------------------------ -do - local id = id("Text") - print(id) -end - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/with.py b/test/python/with.py deleted file mode 100644 index 48fa474..0000000 --- a/test/python/with.py +++ /dev/null @@ -1,2 +0,0 @@ -with id("Text") as id: - print(id) \ No newline at end of file diff --git a/test/python/xl.lua b/test/python/xl.lua deleted file mode 100644 index f6c6552..0000000 --- a/test/python/xl.lua +++ /dev/null @@ -1,94 +0,0 @@ ---/ Compiled using roblox-pyc | Python compiler \-- - - ------------------------------------- BUILT IN ------------------------------- -repeat task.wait() until _G.pyc -local py, import, builtin = _G.pyc(script).py - -local python = builtin.python -local all = builtin.all -local compile = builtin.compile -local script = builtin.script -local range = builtin.range -local int = builtin.int -local print = builtin.print -local open = builtin.open -local id = builtin.id -local asynchronousfunction = builtin.asynchronousfunction -local coroutine = builtin.coroutine -local dict = builtin.dict -local class = builtin.class -local staticmethod = builtin.staticmethod -local str = builtin.str -local string = builtin.string -local operator_in = builtin.operator_in - ------------------------------------------------------------------------------ ---[[ -XL.py (Stands for Extralarge) - -A test script for the roblox-pyc compiler that uses all of the python 3.13 features. - ]] -local y = import("x") -local SSS = py.services.ServerScriptService -for i in range(10) do - print(i) -end -while true do - print("This is an infinite loop") - break -end -do - local f = open("test.txt", "w") - f.write("This is a test file") -end -local function test() - print("This is a function, ran inside of the async function") -end -local async_test = asynchronousfunction(function() - print("This is an async function") - coroutine.yield(test()) -end) -async_test() -local data = dict {["test"] = "This is a test"} -for i in data do - print(i) -end -local Test = class(function(Test) - function Test.__init__(self) - print("This is a class") - end - function Test.test(self) - print("This is a class method") - end - function Test.static_test() - print("This is a static method") - end - Test.static_test = staticmethod(Test.static_test) - function Test.class_test(cls) - print("This is a class method") - end - Test.class_test = classmethod(Test.class_test) - return Test -end, {}) -local new_test = Test() -new_test.test() -new_test.static_test() -new_test.class_test() -local string = "This" -local string2 = "This is a test string" -if (not operator_in(string, string2)) then - print("x is not in y") -else - print("x is in y") -end - ------------------------------------- END ------------------------------------ -if script:IsA("ModuleScript") then - return getfenv() -else - repeat task.wait() until _G.pyc - _G.pyc.libs[script] = getfenv() -end ------------------------------------- END ------------------------------------ - diff --git a/test/python/xl.py b/test/python/xl.py deleted file mode 100644 index 67ee62d..0000000 --- a/test/python/xl.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -XL.py (Stands for Extralarge) - -A test script for the roblox-pyc compiler that uses all of the python 3.13 features. -""" - -# Imports -import x as y - -SSS = py.services.ServerScriptService - -for i in range(10): - print(i) - -while True: - print("This is an infinite loop") - break - -with open("test.txt", "w") as f: - f.write("This is a test file") - -def test(): - print("This is a function, ran inside of the async function") - -async def async_test(): - print("This is an async function") - await test() - -async_test() - -data = { - "test": "This is a test" -} - -for i in data: - print(i) - -class Test: - def __init__(self): - print("This is a class") - - def test(self): - print("This is a class method") - - @staticmethod - def static_test(): - print("This is a static method") - - @classmethod - def class_test(cls): - print("This is a class method") - -new_test = Test() -new_test.test() -new_test.static_test() -new_test.class_test() - -string = "This" -string2 = "This is a test string" - -if string not in string2: - print("x is not in y") -else: - print("x is in y")