diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index faa19a5..de5f210 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -30,17 +30,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- pip install pylint autopep8
+ pip install autopep8
- # Step 4: Run pylint on specified files
- - name: Run pylint on specified files
- id: pylint
- run: |
- pylint_output=$(pylint $(git ls-files '*.py' | grep -vE '(^tests/|^docs/)') --output-format=text) || true
- echo "$pylint_output"
- echo "::set-output name=pylint_output::$pylint_output"
-
- # Step 5: Apply autopep8 fixes
- name: Apply autopep8 fixes
run: |
autopep8 --in-place --aggressive --aggressive $(git ls-files '*.py' | grep -vE '(^tests/|^docs/)')
@@ -56,57 +47,46 @@ jobs:
git push origin main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- build-windows:
- runs-on: windows-latest
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-latest]
+
steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Compile for Windows (32-bit & 64-bit)
- run: |
- clang -shared -m32 -o restructuredpython/lib/io32.dll restructuredpython/include/io.c
- clang -shared -m64 -o restructuredpython/lib/io64.dll restructuredpython/include/io.c
-
- - name: Upload Windows artifacts
- uses: actions/upload-artifact@v4
- with:
- name: windows-libs
- path: restructuredpython/lib/io*.dll
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-python@v5
+
+ - name: Install cibuildwheel
+ run: python -m pip install --upgrade pip cibuildwheel setuptools wheel toml
- build-linux:
+ - name: Build wheels
+ run: python -m cibuildwheel
+ - uses: actions/upload-artifact@v4
+ with:
+ name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
+ path: ./wheelhouse/*.whl
+ build_sdist:
+ name: Make SDist
runs-on: ubuntu-latest
steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Compile for Linux (.so)
- run: |
- gcc -shared -fPIC -o restructuredpython/lib/io.so restructuredpython/include/io.c
-
- - name: Upload Linux artifacts
- uses: actions/upload-artifact@v4
- with:
- name: linux-libs
- path: restructuredpython/lib/io.so
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Optional, use if you use setuptools_scm
+ submodules: true # Optional, use if you have submodules
+
+ - name: Build SDist
+ run: pipx run build --sdist
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: cibw-sdist
+ path: dist/*.tar.gz
- build-macos:
- runs-on: macos-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Compile for macOS (.dylib)
- run: |
- clang -shared -fPIC -fdeclspec -o restructuredpython/lib/io.dylib restructuredpython/include/io.c
-
- - name: Upload macOS artifacts
- uses: actions/upload-artifact@v4
- with:
- name: macos-libs
- path: restructuredpython/lib/io.dylib
publish:
runs-on: ubuntu-latest
- needs: [build-windows, build-linux, build-macos]
+ needs: [build, build_sdist]
environment:
name: pypi
permissions:
@@ -115,10 +95,12 @@ jobs:
- name: Checkout code
uses: actions/checkout@v2
- - name: Download all compiled libraries
+ - name: Download all wheels
uses: actions/download-artifact@v4
with:
- path: restructuredpython/lib/
+ pattern: cibw-*
+ path: dist
+ merge-multiple: true
- name: Set up Python
uses: actions/setup-python@v2
@@ -128,11 +110,12 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- pip install twine setuptools wheel build toml
-
- - name: Build the package with compiled shared libraries
+ pip install toml
+ - name: Extract version from pyproject.toml
+ id: extract_version
run: |
- python3 -m build
+ python -c "import toml; print(toml.load('pyproject.toml')['project']['version'])" > version.txt
+ echo "release_version=$(cat version.txt)" >> $GITHUB_ENV
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
@@ -144,8 +127,7 @@ jobs:
tag_name: "v${{ env.release_version }}"
name: "${{ env.release_version }}"
files: |
- dist/*.whl
- dist/*.tar.gz
+ dist/*
body: |
View the [changelog](https://restructuredpython.readthedocs.io/en/latest/changelog.html) for information about this release.
env:
diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml
index 2a9b481..a8b431c 100644
--- a/.github/workflows/python-package.yml
+++ b/.github/workflows/python-package.yml
@@ -1,4 +1,4 @@
-name: Build and Create GitHub Release for PR
+name: Build and Create Github Release for PR
on:
pull_request:
@@ -8,90 +8,63 @@ on:
- reopened
paths-ignore:
- 'docs/**'
- - 'restructuredpython.egg-info/**'
- '.github/**'
- '.gitattributes'
- '.gitignore'
- 'README.md'
jobs:
- Windows:
- runs-on: windows-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
-
- - name: Compile Windows DLLs
- run: |
- clang -shared -m32 -o restructuredpython/lib/io32.dll restructuredpython/include/io.c
- clang -shared -m64 -o restructuredpython/lib/io64.dll restructuredpython/include/io.c
-
-
- - name: Upload Windows artifacts
- uses: actions/upload-artifact@v4
- with:
- name: windows-libs
- path: restructuredpython/lib/io*.dll
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-13, macos-latest]
- Ubuntu:
- runs-on: ubuntu-latest
steps:
- - name: Checkout code
- uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- - name: Compile Linux .so
- run: |
- gcc -shared -fPIC -o restructuredpython/lib/io.so restructuredpython/include/io.c
- - name: Upload Linux artifacts
- uses: actions/upload-artifact@v4
- with:
- name: linux-libs
- path: restructuredpython/lib/io.so
+ - uses: actions/setup-python@v5
- macOS:
- runs-on: macos-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v2
+ - name: Install cibuildwheel
+ run: python -m pip install --upgrade pip cibuildwheel setuptools wheel toml
- - name: Compile macOS .dylib
- run: |
- clang -shared -fPIC -fdeclspec -o restructuredpython/lib/io.dylib restructuredpython/include/io.c
+ - name: Build wheels
+ uses: pypa/cibuildwheel@v3.0.0
- - name: Upload macOS artifacts
- uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@v4
with:
- name: macos-libs
- path: restructuredpython/lib/io.dylib
-
- build-package:
- runs-on: windows-latest
- needs: [Windows, Ubuntu, macOS]
- strategy:
- matrix:
- python-version: ["3.13"]
+ name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
+ path: ./wheelhouse/*.whl
+ build_sdist:
+ name: Make SDist
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ submodules: false
+
+ - name: Build SDist
+ run: pipx run build --sdist
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: cibw-sdist
+ path: dist/*.tar.gz
+ create_release:
+ runs-on: ubuntu-latest
+ needs: [build, build_sdist]
+ permissions:
+ id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v2
- - name: Download all compiled libraries
- uses: actions/download-artifact@v4
- with:
- path: restructuredpython/lib/
-
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ - uses: actions/download-artifact@v4
with:
- python-version: ${{ matrix.python-version }}
-
- - name: Install dependencies
- run: |
- python -m pip install --upgrade pip
- pip install setuptools wheel build
-
- - name: Build the package
- run: |
- python -m build
+ pattern: cibw-*
+ path: dist
+ merge-multiple: true
- name: Create a GitHub release
id: create_release
@@ -99,9 +72,9 @@ jobs:
with:
tag_name: "#${{ github.event.pull_request.number }}"
name: "PR #${{ github.event.pull_request.number }}"
- prerelease: true
files: |
- dist/*.whl
- dist/*.tar.gz
+ dist/*
+ body: |
+ Auto-generated wheels from PR #[${{github.event.pull_request.number}}](https://github.com/sharktide/restructuredpython/pull/${{github.event.pull_request.number}}).
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
diff --git a/.gitignore b/.gitignore
index 771e3dc..da91914 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
dist/*
*.pyc
-build/*
\ No newline at end of file
+build/*
+wheelhouse/*
+restructuredpython.egg-info/**
\ No newline at end of file
diff --git a/compile.bat b/compile.bat
deleted file mode 100644
index 32ab3f5..0000000
--- a/compile.bat
+++ /dev/null
@@ -1,48 +0,0 @@
-@echo off
-setlocal enabledelayedexpansion
-echo This compiles the C libraries in a external enviornment using MSVC, then copies them to the appropriate locations in this repo.
-echo Requirements: xcopy.exe on PATH
-echo Requirements: MSVC cl.exe
-echo Requirements: This must be run from either the Developer PWSH/CMD for VS or the x64 Native Tools Prompt
-
-set SRC_DIR=%CD%
-set DEST=C:\TempBuild
-
-if not exist "%DEST%" mkdir "%DEST%"
-
-xcopy "%SRC_DIR%\*" "%DEST%" /E /H /C /I /exclude:exclude.txt
-
-pushd "C:\TempBuild"
-cl /LD restructuredpython/include/io.c
-
-set /p arch="Was this run from an x64 tools prompt (y/n) >"
-if "%arch%"=="y" (
- for %%F in (io.dll) do xcopy "%%F" "%SRC_DIR%/restructuredpython/lib/windows-libs/io64.dll" /Y
-) else (
- for %%F in (io.dll) do xcopy "%%F" "%SRC_DIR%/restructuredpython/lib/windows-libs/io32.dll" /Y
-)
-
-echo Deleting copied files
-
-del /Q C:\TempBuild
-
-popd
-
-echo Operation Completed
-
-endlocal
-
-
-@REM Copyright 2025 Rihaan Meher
-
-@REM Licensed under the Apache License, Version 2.0 (the "License");
-@REM you may not use this file except in compliance with the License.
-@REM You may obtain a copy of the License at
-
-@REM http://www.apache.org/licenses/LICENSE-2.0
-
-@REM Unless required by applicable law or agreed to in writing, software
-@REM distributed under the License is distributed on an "AS IS" BASIS,
-@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@REM See the License for the specific language governing permissions and
-@REM limitations under the License.
\ No newline at end of file
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 289d43d..6a2fe38 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -1,4 +1,4 @@
-reStructuredPython Changelog
+Changelog
=============================
*Note: This changelog skips version 0.1.1*
@@ -8,6 +8,13 @@ Major release 2
.. raw:: html
+
+ 2.5.0
+
+ - Introduced <OPTIMIZE> markers, which allow restructuredpython code to be executed faster than cpython would normally when restructuredpython is installed.
+
+
+
2.4.0
diff --git a/docs/source/compiler/overview.rst b/docs/source/compiler/overview.rst
deleted file mode 100644
index ab51bc7..0000000
--- a/docs/source/compiler/overview.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-Overview
-========
-
-reStructuredPython, also known as 'rePython', is an alternative Python implementation that introduces JavaScript-like syntax for a cleaner and more readable code structure. The reStructuredPython compiler converts ``.repy`` files into standard Python code.
-
-Key Features
-------------
-
-* **Curly-Braced Control Statements:** Control structures in reStructuredPython utilize curly braces, similar to JavaScript, enhancing readability.
-
-Installation
-------------
-To install the reStructuredPython compiler, use pip:
-
-.. code-block:: bash
-
- pip install restructuredpython
-
-Usage
------
-
-After installation, compile a .repy file by running:
-
-.. code-block:: bash
-
- repy path/to/your/file.repy
-
-Example
--------
-
-Consider the following reStructuredPython code in ``example.repy``:
-
-.. code-block:: repy
-
- x = int(input("Enter a number: "))
- if (x > 0) {
- print("Positive number")
- } else if (x < 0) {
- print("Negative number")
- } else {
- print("Zero")
- }
-
-Running ``repy example.repy`` compiles this into standard Python code, which can then be executed as usual.
-
-*Note: reStructuredPython is designed for users who prefer a JavaScript-like syntax within the Python ecosystem. While it offers syntactic differences, the compiled output remains standard Python code.*
-
-
diff --git a/docs/source/conf.py b/docs/source/conf.py
index df497d3..efadd45 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -10,7 +10,7 @@
copyright = '2025, Rihaan Meher'
author = 'Rihaan Meher'
-release = '2.4.0'
+release = '2.5.0'
html_favicon = "_static/icon.png"
# -- General configuration ---------------------------------------------------
diff --git a/docs/source/compiler/error_index/REPY-0001.rst b/docs/source/error_index/REPY-0001.rst
similarity index 100%
rename from docs/source/compiler/error_index/REPY-0001.rst
rename to docs/source/error_index/REPY-0001.rst
diff --git a/docs/source/compiler/error_index/REPY-0002.rst b/docs/source/error_index/REPY-0002.rst
similarity index 100%
rename from docs/source/compiler/error_index/REPY-0002.rst
rename to docs/source/error_index/REPY-0002.rst
diff --git a/docs/source/compiler/error_index/REPY-0003.rst b/docs/source/error_index/REPY-0003.rst
similarity index 100%
rename from docs/source/compiler/error_index/REPY-0003.rst
rename to docs/source/error_index/REPY-0003.rst
diff --git a/docs/source/compiler/error_index/REPY-0004.rst b/docs/source/error_index/REPY-0004.rst
similarity index 100%
rename from docs/source/compiler/error_index/REPY-0004.rst
rename to docs/source/error_index/REPY-0004.rst
diff --git a/docs/source/compiler/error_index/REPY-0005.rst b/docs/source/error_index/REPY-0005.rst
similarity index 90%
rename from docs/source/compiler/error_index/REPY-0005.rst
rename to docs/source/error_index/REPY-0005.rst
index 5580ad9..b6fbc8b 100644
--- a/docs/source/compiler/error_index/REPY-0005.rst
+++ b/docs/source/error_index/REPY-0005.rst
@@ -1,4 +1,4 @@
-Case definition on the same line as RBRACE (REPY-0004)
+Case definition on the same line as RBRACE (REPY-0005)
==========================================================
Description
diff --git a/docs/source/error_index/REPY-0006.rst b/docs/source/error_index/REPY-0006.rst
new file mode 100644
index 0000000..06ec03c
--- /dev/null
+++ b/docs/source/error_index/REPY-0006.rst
@@ -0,0 +1,51 @@
+Warning: ... directive will require ... to be installed (REPY-0006)
+===================================================================
+
+This warning means that a certain directive you are using in your code (a common one being ) will require a specific python package (eg. restructuredpython, this package) to be installed at runtime.
+
+What this means in simpler terms is that a certain feature that you are using like :doc:`` will be compiled into python, but will require recources from another python package via import. (oftentimes restructuredpython itself)
+
+For example, this code using the :doc:``will raise this warning during transpilation and will compile to this:
+
+``ops.repy``
+
+.. code-block:: repy
+
+ print("Running unoptimized loop:")
+ import time
+ start = time.perf_counter()
+ for i in range(10_000_000) {
+ temp = str(i) * 10
+ }
+ end = time.perf_counter()
+ print("Unoptimized loop time:", round(end - start, 4), "seconds")
+
+
+ for j in range(10_000_000) {
+ temp = str(j) * 10
+ }
+
+Now, if transpiled using ``repy ops.repy``, this will warn of REPY-0006, and transpile to this:
+
+``ops.py``
+
+.. code-block::python
+
+ from restructuredpython.predefined.subinterpreter import optimize_loop
+ print("Running unoptimized loop:")
+ import time
+ start = time.perf_counter()
+ for i in range(10_000_000) :
+ temp = str(i) * 10
+ end = time.perf_counter()
+ print("Unoptimized loop time:", round(end - start, 4), "seconds")
+
+ @optimize_loop(gct=True, profile=True)
+ def _repy_optimized_loop_0():
+ for j in range(10_000_000) :
+ temp = str(j) * 10
+ _repy_optimized_loop_0()
+
+You can see how this code now has an import from the ``restructuredpython`` module. This is necessary for features using the <...> syntax as these are markers to do complex things and there isn't an easy way to transpile them to pure python.
+
+Never fear, however! You can usually either run it directly with :doc:`repycl ` or make the generated python code runnable by just adding the requested package specified to your ``requirements.txt`` or the equivalent.
\ No newline at end of file
diff --git a/docs/source/compiler/error_index/index.rst b/docs/source/error_index/index.rst
similarity index 93%
rename from docs/source/compiler/error_index/index.rst
rename to docs/source/error_index/index.rst
index 86989e6..2e50084 100644
--- a/docs/source/compiler/error_index/index.rst
+++ b/docs/source/error_index/index.rst
@@ -11,3 +11,4 @@ This section contains all the error codes and their explanations.
REPY-0003
REPY-0004
REPY-0005
+ REPY-0006
diff --git a/docs/source/guides/Getting_Started.rst b/docs/source/guides/Getting_Started.rst
index 746ad84..e21677a 100644
--- a/docs/source/guides/Getting_Started.rst
+++ b/docs/source/guides/Getting_Started.rst
@@ -1,2 +1,106 @@
Getting started
-===============
\ No newline at end of file
+===============
+
+Welcome to reStructuredPython! 🎉
+This guide will walk you through installing the compiler, writing your first `.repy` program, and compiling or running it.
+
+What is reStructuredPython?
+---------------------------
+
+reStructuredPython (aka **rePython**) is a superset of Python designed to:
+
+- Use modern syntax inspired by JavaScript, C#, C/C++ and many other languages
+- Compile back to 100% standard Python
+- Support modular language features (like `|>` pipelines, braced blocks, multiline comments, and optional optimizations)
+
+It's designed to look modern, feel powerful, and remain compatible with the Python ecosystem.
+
+---
+
+Installation
+------------
+
+Install the latest version using pip:
+
+.. code-block:: shell
+
+ pip install --upgrade restructuredpython
+
+Make sure ``repy`` and ``repycl`` are now available in your terminal:
+
+.. code-block:: shell
+
+ repy -h
+ repycl -h
+
+---
+
+Writing Your First Program
+--------------------------
+
+Create a file named `hello.repy`:
+
+.. code-block:: repy
+
+ /* This is a multiline
+ comment */
+
+ #hello.repy
+ name = "sharktide"
+ def say_hello(name) {
+ print("reStructuredPython is Awesome!")
+ return name
+ }
+ def say_bye(name) {
+ print(f'Bye {name}')
+ }
+ name |> say_hello |> say_bye
+
+---
+
+Transpile or Run
+----------------
+
+To compile `.repy` into `.py`:
+
+.. code-block:: shell
+
+ repy hello.repy
+
+This will generate `hello.py`.
+
+To compile **and run** the program:
+
+.. code-block:: shell
+
+ repycl hello.repy
+
+The `repycl` command handles compilation and runtime execution, especially for features like `optimize_loop` and `strict_types`.
+
+---
+
+.. Optional: Enable/Disable Features
+.. ---------------------------------
+
+.. reStructuredPython is **modular** — you can enable or disable language features using a `repyconfig.toml`.
+
+.. Example:
+
+.. .. code-block:: toml
+
+.. .. [features]
+.. control_blocks = true
+.. pipelines = false
+.. optimizations = true
+
+.. See :doc:`Feature Toggles ` for more details.
+
+.. ---
+
+Next Steps
+----------
+
+- 📚 Explore the :doc:`Syntax Guide <../reference/Syntax_Guide>` for full syntax support
+- ⚙️ Learn more about :doc:`repy ` and :doc:`repycl <../reference/repycl>`
+- 🚀 Check out some of the :doc:`features `
+Happy coding!
diff --git a/docs/source/guides/Install.rst b/docs/source/guides/Install.rst
index c4ee819..87082a5 100644
--- a/docs/source/guides/Install.rst
+++ b/docs/source/guides/Install.rst
@@ -43,10 +43,3 @@ Consider the following reStructuredPython code in ``example.repy``:
Running ``repy example.repy`` compiles this into standard Python code, which can then be executed as usual.
-*Note: reStructuredPython is designed for users who prefer a JavaScript-like syntax within the Python ecosystem. While it offers syntactic differences, the compiled output remains standard Python code.*
-
-
-
-
-
-
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 3992d18..3e8b78b 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -56,13 +56,15 @@ Join the reStructuredPython community to contribute, ask questions, and stay upd
:maxdepth: 2
:caption: Contents
- compiler/overview
- compiler/error_index/index
+ error_index/index
changelog
guides/Getting_Started
guides/Install
reference/index
reference/Builtin_Decorators
+ reference/optimize
+ reference/repycl
+ reference/repy
tutorials/Example_Programs
roadmap
diff --git a/docs/source/reference/Exposed_APIs/.parse().rst b/docs/source/reference/Exposed_APIs/.parse().rst
index 2954dbd..2891d8a 100644
--- a/docs/source/reference/Exposed_APIs/.parse().rst
+++ b/docs/source/reference/Exposed_APIs/.parse().rst
@@ -1,4 +1,4 @@
-.check_syntax()
+.parse()
===============
This function parses reStructuredPython
diff --git a/docs/source/reference/Features/OPTIMIZE.rst b/docs/source/reference/Features/OPTIMIZE.rst
new file mode 100644
index 0000000..66824d1
--- /dev/null
+++ b/docs/source/reference/Features/OPTIMIZE.rst
@@ -0,0 +1,26 @@
+ Directives
+=====================
+
+reStructuredPython allows you to apply runtime optimizations using special compiler directives and decorators.
+
+.. code-block:: python
+
+
+ for i in range(10_000_000) {
+ temp = str(i) * 10
+ }
+
+
+.. note::
+ Optimizations currently support loops and functions only.
+
+Arguments for `optimize_loop` and `optimize_function` include:
+
+- ``gct=True``: Enable garbage collection tracking.
+- ``profile=True``: Enable execution time logging.
+
+This will generate a python file that imports the optimization decorators from this ( the ``restructuredpython`` package ), so you will need to have this packag installed via pip on systems running your compiled, optimized program.
+
+However, as of 2.5.0, you could technically open the generated python file, remove the imports from ``restructuredpython``, and instead use ``include 'subinterpreter.optimize'``. However, this is expictily NOT recommended as it will break in future versions of reStructuredPython and will include an annoying copyright header in the generated file.
+
+We recommend running this with ``repycl`` the restructuredpython interpreter & launcher.
diff --git a/docs/source/reference/Features/chaining.rst b/docs/source/reference/Features/chaining.rst
new file mode 100644
index 0000000..0c5eace
--- /dev/null
+++ b/docs/source/reference/Features/chaining.rst
@@ -0,0 +1,35 @@
+Function Chaining
+=================
+
+ In reStructuredPython 0.7.0, a new feature called function chaning was created. You can chain functions using the ``|>`` operartor to increase readablility and efficency
+
+ Example:
+
+ .. code-block:: repy
+
+ def preprocess(data) {
+ return data * 2
+ }
+ def analyze(data) {
+ return data + 3
+ }
+ def summarize(data) {
+ return f"Result: {data}"
+ }
+ result = 5 |> preprocess |> analyze |> summarize
+ print(result)
+
+ This compiles into:
+
+ .. code-block:: python
+
+ def preprocess(data) :
+ return data * 2
+ def analyze(data) :
+ return data + 3
+ def summarize(data) :
+ return f"Result: {data}"
+ result = summarize(analyze(preprocess(5)))
+ print(result)
+
+ This is best used in conjunction with header files.
\ No newline at end of file
diff --git a/docs/source/reference/Features/comments.rst b/docs/source/reference/Features/comments.rst
new file mode 100644
index 0000000..0b55b0f
--- /dev/null
+++ b/docs/source/reference/Features/comments.rst
@@ -0,0 +1,23 @@
+Multiline Comments
+==================
+
+ In reStructuredPython 0.8.0, we added multiline comments with an near identical syntax to JavaScript to make large comments in programs easier to write, a feature that python doesn't have.
+
+ Example:
+
+ .. code-block:: repy
+
+ /* This is a multiline comment
+ that spans multiple lines */
+ if True:
+ print("Hello World")
+ This compiles into:
+
+ .. code-block:: repy
+
+ # This is a multiline comment
+ # that spans multiple lines
+ if True:
+ print("Hello World")
+
+ This feature is extremely useful for including documentation in files when a docstring is not wanted
diff --git a/docs/source/reference/Features/control.rst b/docs/source/reference/Features/control.rst
new file mode 100644
index 0000000..eec78e0
--- /dev/null
+++ b/docs/source/reference/Features/control.rst
@@ -0,0 +1,38 @@
+Control Loop Syntax
+===================
+
+Control loops and class/function definitions/with statements etc. **MAY** use curly brackets instead of ":" like in regular Python. However, using regular python will **NOT** throw an error.
+
+.. code-block:: repy
+
+ x = int(input('gimme a num'))
+ if x == 2 {
+ print("x is 2!")
+ if (input("say 'yes'") == 'yes') {
+ print('Hi')
+ }
+ }
+ elif x < 2 {
+ print("x is less than 2!")
+ }
+ else {
+ print("x is greater than 2!")
+ }
+
+ for i in range(10) {
+ print(i)
+ }
+
+ def my_function(param) {
+ return param
+ }
+
+However, make sure not to do something like this:
+
+.. code-block:: python
+
+ if (condition) {
+ pass
+ } elif (somethingelse) { # <--- } else or } elif or } def or } case etc. not allowed and will throw an error!
+ pass
+ }
\ No newline at end of file
diff --git a/docs/source/reference/Features/decorators.rst b/docs/source/reference/Features/decorators.rst
new file mode 100644
index 0000000..571c2e8
--- /dev/null
+++ b/docs/source/reference/Features/decorators.rst
@@ -0,0 +1,4 @@
+Built-in Decorators
+===================
+
+See the :doc:`Builtin Decorators Guide `.
diff --git a/docs/source/reference/Features/headers.rst b/docs/source/reference/Features/headers.rst
new file mode 100644
index 0000000..94bd6e0
--- /dev/null
+++ b/docs/source/reference/Features/headers.rst
@@ -0,0 +1,29 @@
+Header Files
+============
+
+ reStructuredPython offers a new and exciting feature not present in regular python. The addition of header files, written in a ``.cdata`` or ``.repy`` file extension are regular ``.repy`` files written in reStructuredPython that are compiled and automatically prepended in the final compilation of a ``.repy`` file.
+
+ Example usage:
+
+ .. code-block:: repy
+
+ include 'path/to/my/file.repy'
+
+ afunctiondefinedintheheaderfile()
+
+ ``file.cdata``:
+
+ .. code-block:: repy
+
+ def afunctiondefinedintheheaderfile() {
+ print('This function was made in a header file')
+ }
+
+ Result:
+
+ .. code-block:: python
+
+ def afunctiondefinedintheheaderfile() :
+ print('This function was made in a header file')
+
+ afunctiondefinedintheheaderfile()
diff --git a/docs/source/reference/Features/index.rst b/docs/source/reference/Features/index.rst
new file mode 100644
index 0000000..9bccb6d
--- /dev/null
+++ b/docs/source/reference/Features/index.rst
@@ -0,0 +1,19 @@
+Language Features
+=================
+
+This section includes a comprehensive list of all the features available in the reStructuredPython programming language.
+
+reStructuredPython is designed to be modular. You only use the features you need — for example, using JavaScript-style control blocks without pipelines, or enabling runtime optimizations without any syntax changes.
+
+Each of these pages will describe one feature of the reStructuredPython **syntax** or provide a description of non-syntax related things
+
+.. toctree::
+ :maxdepth: 2
+
+ chaining
+ comments
+ control
+ decorators
+ headers
+ blocks
+ OPTIMIZE
diff --git a/docs/source/reference/Syntax_Guide.rst b/docs/source/reference/Syntax_Guide.rst
deleted file mode 100644
index 02488ab..0000000
--- a/docs/source/reference/Syntax_Guide.rst
+++ /dev/null
@@ -1,126 +0,0 @@
-Syntax Guide
-============
-
-reStructuredPython introduces a syntax that combines Python's functionality with JavaScript-like conventions. Below are some key syntax elements:
-
-1. **Control Loop Syntax** Latest in 0.6.0
-
- Control loops and class/function definitions use curly brackets instead of ":" like in regular Python
-
- .. code-block:: repy
-
- x = int(input('gimme a num'))
- if x == 2 {
- print("x is 2!")
- if (input("say 'yes'") == 'yes') {
- print('Hi')
- }
- }
- elif x < 2 {
- print("x is less than 2!")
- }
- else {
- print("x is greater than 2!")
- }
-
- for i in range(10) {
- print(i)
- }
-
- def my_function(param) {
- return param
- }
-
-2. **Header Files** Latest in 0.5.0
-
- reStructuredPython offers a new and exciting feature not present in regular python. The addition of header files, written in a ``.cdata`` file extension are regular ``.repy`` files written in reStructuredPython that are compiled and automatically included in the final compilation of a ``.repy`` file.
-
- Example usage:
-
- .. code-block:: repy
-
- include 'path/to/my/file.cdata'
-
- afunctiondefinedintheheaderfile()
-
- ``file.cdata``:
-
- .. code-block:: repy
-
- def afunctiondefinedintheheaderfile() {
- print('This function was made in a header file')
- }
-
- Result:
-
- .. code-block:: python
-
- def afunctiondefinedintheheaderfile() :
- print('This function was made in a header file')
-
- afunctiondefinedintheheaderfile()
-
-3. **Function Chaining** Latest in 0.7.0
-
- In reStructuredPython 0.7.0, a new feature called function chaning was created. In 0.7.0, you can chain functions using the ``|>`` operartor to increase readablility and efficency
-
- Example:
-
- .. code-block:: repy
-
- def preprocess(data) {
- return data * 2
- }
- def analyze(data) {
- return data + 3
- }
- def summarize(data) {
- return f"Result: {data}"
- }
- result = 5 |> preprocess |> analyze |> summarize
- print(result)
-
- This compiles into:
-
- .. code-block:: python
-
- def preprocess(data) :
- return data * 2
- def analyze(data) :
- return data + 3
- def summarize(data) :
- return f"Result: {data}"
- result = summarize(analyze(preprocess(5)))
- print(result)
-
- This is best used in conjunction with header files.
-
-4. **Multiline Comments** Latest in 0.8.0
-
- In reStructuredPython 0.8.0, we added multiline comments with an near identical syntax to JavaScript to make large comments in programs easier to write, a feature that python doesn't have.
-
- Example:
-
- .. code-block:: repy
-
- /* This is a multiline comment
- that spans multiple lines */
- if True:
- print("Hello World")
- This compiles into:
-
- .. code-block:: repy
-
- # This is a multiline comment
- # that spans multiple lines
- if True:
- print("Hello World")
-
- This should be pretty easy to grasp for a developer who knows the syntax of the C and JavaScript familes to use.
- This feature is also useful for including documentation in files when a docstring is too long or not an option.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst
index 579cf37..ee85ef1 100644
--- a/docs/source/reference/index.rst
+++ b/docs/source/reference/index.rst
@@ -1,12 +1,14 @@
Reference
=========
-The reference section provides detailed information about the built-in functions, syntax, repyconfig.toml, and exposed APIs of reStructuredPython.
+The reference section provides detailed information about the built-in functions, syntax, repyconfig.toml, and exposed python APIs of reStructuredPython.
.. toctree::
:maxdepth: 2
- Syntax_Guide
+ repycl
+ repy
Builtin_Decorators/index
repyconfig.toml
Exposed_APIs/index
+ Features/index
diff --git a/docs/source/reference/repy.rst b/docs/source/reference/repy.rst
new file mode 100644
index 0000000..b645435
--- /dev/null
+++ b/docs/source/reference/repy.rst
@@ -0,0 +1,78 @@
+repy Command
+===============
+
+The ``repy`` command is the original compiler for reStructuredPython.
+
+It takes a `.repy` (reStructuredPython) file and compiles it into standard Python (`.py`) output.
+
+How to use
+----------
+
+.. code-block:: shell
+
+ repy path/to/source.repy
+
+This will generate a Python file in the same directory named `source.py`.
+
+---
+
+Supported Features
+------------------
+
+✅ The `repy` command processes the following features:
+
+- Function Chaining :doc:`Features/chaining`
+- Multiline Comments :doc:`Features/comments`
+- Optional curly brackets on control loops (like c/cpp/cs/js) :doc:`Features/control`
+- Built-in Decorators :doc:`Builtin_Decorators/index`
+- Header Files :doc:`Features/headers`
+- Regular Python (thats right: regular python is 100% compatible! See :doc:`Features/index` for more info)
+
+❌ The `repy` command **does** not processes the following features:
+
+- Runtime execution (use :doc:`repycl ` for that)
+
+⚠️ The `repy` command **will** process the following features, but the compiled python will depend on the ``restructuredpython`` module to be installed.
+
+- markers
+
+---
+
+.. CLI Options
+.. -----------
+
+.. Optional arguments:
+
+.. - ``-o `` or ``--output ``
+.. Output path for the compiled `.py` file.
+
+.. - ``--check``
+.. Run syntax checks only; no output file is created.
+
+.. - ``--mode classic|strict``
+.. Choose a parsing mode (defaults to `classic`).
+
+.. Example:
+
+.. .. code-block:: shell
+
+.. repy my_code.repy --output compiled.py --mode strict
+
+.. ---
+
+When to Use repy vs repycl
+---------------------------
+
+Use ``repy`` when:
+
+- You just want to compile `.repy` to `.py`
+- You're integrating with another Python toolchain
+- You're distributing `.py` files
+
+Use ``repycl`` when:
+
+- You want to compile and run in one step
+- You depend on runtime features like optimizations
+- You're using features that need <...> markers (eg. , and don't want to compile
+
+See also: :doc:`repycl `
diff --git a/docs/source/reference/repycl.rst b/docs/source/reference/repycl.rst
new file mode 100644
index 0000000..2ed2ee6
--- /dev/null
+++ b/docs/source/reference/repycl.rst
@@ -0,0 +1,14 @@
+repycl Command
+==============
+
+The ``repycl`` command compiles and directly executes reStructuredPython code **with compiler optimizations** in one step.
+
+.. code-block:: shell
+
+ repycl path/to/file.repy
+
+It automatically compiles your code to and then runs it. This is useful for:
+
+- Running code without transpiling intermediate `.py` files
+- Runtime optimizations and performance testing
+- Debugging optimized loops or runtime decorators
\ No newline at end of file
diff --git a/docs/source/roadmap.rst b/docs/source/roadmap.rst
index 7c6f22e..8405bfa 100644
--- a/docs/source/roadmap.rst
+++ b/docs/source/roadmap.rst
@@ -3,4 +3,4 @@ Roadmap
Nothing to see here!
-The content of releases 2.5.0 hass not been decided yet, although will probably include an overhaul to the argparsing
+We don't know what we'll have in 2.6.0 but it will be soon!
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 362996a..31d4345 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,13 +1,14 @@
[build-system]
-requires = ["setuptools"]
+requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"
[project]
name = "restructuredpython"
-version = "2.4.0"
+version = "2.5.0"
+requires-python = ">= 3.10"
description = "A superset of Python with many new features, including full JS integration, multiline comments, header files, and optional curly brackets around control statements"
authors = [{name = "Rihaan Meher", email = "meherrihaan@gmail.com"}]
-license-files = ["LICENSE"]
+license = { text = "Apache-2.0" }
readme = "README.md"
classifiers = [
"Programming Language :: Python :: 3",
@@ -19,10 +20,20 @@ classifiers = [
dependencies = [
"textfmt"
]
+
[project.scripts]
repy = "restructuredpython.restructuredpython:main"
repycl = "restructuredpython.restructuredpython:launch"
[tool.setuptools]
packages = ["restructuredpython"]
+ext-modules = [
+ {name = "restructuredpython.api.libio", sources = ["restructuredpython/lib/io.c"]}
+]
+[project.urls]
+Homepage = "https://restructuredpython.rf.gd"
+Documentation = "https://restructuredpython.readthedocs.org"
+Repository = "https://github.com/sharktide/restructuredpython.git"
+Issues = "https://github.com/sharktide/restructuredpython/issues"
+Changelog = "https://restructuredpython.readthedocs.io/en/latest/changelog.html"
\ No newline at end of file
diff --git a/restructuredpython.egg-info/PKG-INFO b/restructuredpython.egg-info/PKG-INFO
deleted file mode 100644
index 8ed7729..0000000
--- a/restructuredpython.egg-info/PKG-INFO
+++ /dev/null
@@ -1,53 +0,0 @@
-Metadata-Version: 2.4
-Name: restructuredpython
-Version: 2.4.0
-Summary: A superset of Python with many new features, including full JS integration, multiline comments, header files, and optional curly brackets around control statements
-Author-email: Rihaan Meher
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: 3.13
-Description-Content-Type: text/markdown
-License-File: LICENSE
-Requires-Dist: textfmt
-Dynamic: license-file
-
-# This is reStructuredPython 2
-
-
-[](https://pepy.tech/projects/restructuredpython)
-
-
-The all in one, new python.
-reStructuredPython aka 'rePython' is a superset of python with many new features, such as header files, similar to C and C++, Optional Javascript-like syntax with curly brackets {} around control loops, function chanining and more. All the features can be found in the syntax/feature guide of our documentation https://restructuredpython.readthedocs.io/en/latest/reference/Syntax_Guide.html
-
-To download the reStructuredPython compiler using the python package index:
-
-```shell
-pip install --upgrade restructuredpython
-```
-Download our vscode extension with intellisense support [from the visual studio marketplace](https://marketplace.visualstudio.com/items?itemName=RihaanMeher.restructuredpython)
-
-To use the reStructuredPython compiler:
-
-```shell
-repy path/to/your/file.repy
-```
-It is that simple!
-
-# Basics
-reStructuredPython code is written in a file extension .repy and reStructuredPython header files are written with the file extension .cdata. Functions can now be chained in a more readable syntax. Control loops an be defined with curly brackets, instead of colons. View entries 1, 2, and 3 of the [syntax guide](https://restructuredpython.readthedocs.io/en/latest/reference/Syntax_Guide.html) for more details.
-
-# Contributing
-
-Please contribute and raise issues! We just started and this is a pioneering project. Fork the repository, make your changes, update the documentation in the docs/* folder, add examples (if applicable) in the tests/.repy and their compiled versions in tests/.py directory as well as in docs/source/tutorials/programs and in docs/source/tutorials/compiled_programs. Once you have ensured all features work of the compiler by test-compiling the other files in tests/.repy/*, make a pull request with the github issue number is applicable, short concise title and description of your changes. Warining: The first paragraph of the pull request description will go to be part of the changelong, so keep it short and clear. PLEASE DO NOT label your changes as a new version. That will be done manually or by a bot.
-
-# Changelog
-
-View the changelog at https://restructuredpython.readthedocs.io/en/latest/changelog.html
-
-# Common mistakes
-
-These mistakes will reslut in a syntax error thrown by the REPY compiler or invalid python.
-View the error index at https://restructuredpython.readthedocs.io/en/latest/compiler/error_index/
diff --git a/restructuredpython.egg-info/SOURCES.txt b/restructuredpython.egg-info/SOURCES.txt
deleted file mode 100644
index 735012e..0000000
--- a/restructuredpython.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-LICENSE
-MANIFEST.in
-README.md
-pyproject.toml
-restructuredpython/__init__.py
-restructuredpython/check_syntax.py
-restructuredpython/cload.py
-restructuredpython/parser.py
-restructuredpython/restructuredpython.py
-restructuredpython/tempload.py
-restructuredpython.egg-info/PKG-INFO
-restructuredpython.egg-info/SOURCES.txt
-restructuredpython.egg-info/dependency_links.txt
-restructuredpython.egg-info/entry_points.txt
-restructuredpython.egg-info/requires.txt
-restructuredpython.egg-info/top_level.txt
-restructuredpython/include/io.c
-restructuredpython/lib/DO_NOT_MODIFY_THIS_DIR.txt
-restructuredpython/lib/windows-libs/io64.dll
-restructuredpython/predefined/__init__.py
-restructuredpython/predefined/decorators.py
-restructuredpython/predefined/decorators/access_control.py
-restructuredpython/predefined/decorators/logging.py
-restructuredpython/predefined/decorators/memoization.py
-restructuredpython/predefined/decorators/retry.py
-restructuredpython/predefined/decorators/strict_types.py
-restructuredpython/predefined/decorators/timer.py
\ No newline at end of file
diff --git a/restructuredpython.egg-info/dependency_links.txt b/restructuredpython.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/restructuredpython.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/restructuredpython.egg-info/entry_points.txt b/restructuredpython.egg-info/entry_points.txt
deleted file mode 100644
index ced7f1c..0000000
--- a/restructuredpython.egg-info/entry_points.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-[console_scripts]
-repy = restructuredpython.restructuredpython:main
-repycl = restructuredpython.restructuredpython:launch
diff --git a/restructuredpython.egg-info/requires.txt b/restructuredpython.egg-info/requires.txt
deleted file mode 100644
index 4d43d66..0000000
--- a/restructuredpython.egg-info/requires.txt
+++ /dev/null
@@ -1 +0,0 @@
-textfmt
diff --git a/restructuredpython.egg-info/top_level.txt b/restructuredpython.egg-info/top_level.txt
deleted file mode 100644
index 049b6a6..0000000
--- a/restructuredpython.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-restructuredpython
diff --git a/restructuredpython/__init__.py b/restructuredpython/__init__.py
index 30c8b6f..5b5fc05 100644
--- a/restructuredpython/__init__.py
+++ b/restructuredpython/__init__.py
@@ -1,3 +1,17 @@
+# Copyright 2025 Rihaan Meher
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
from .restructuredpython import *
from .parser import *
diff --git a/restructuredpython/check_syntax.py b/restructuredpython/check_syntax.py
index c283741..6732720 100644
--- a/restructuredpython/check_syntax.py
+++ b/restructuredpython/check_syntax.py
@@ -1,7 +1,20 @@
-from textformat import *
+# Copyright 2025 Rihaan Meher
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
-def check_syntax(input_lines):
+from textformat import *
+import warnings
+def check_syntax(input_lines, mode="classic"):
"""
Check restructuredpython syntax
param: input_lines: list object of all input lines to check
@@ -36,6 +49,11 @@ def check_syntax(input_lines):
i +
1}. (REPY-0004){
bcolors.ENDC}")
+
if line.startswith('} case'):
raise SyntaxError(
f"{bcolors.BOLD}{bcolors.FAIL}Misplaced 'case' statement at line {i + 1}. (REPY-0005){bcolors.ENDC}")
+
+ if mode == "classic" and line.startswith(" directives will require restructuredpython installed as a python package during runtime to make use of optimizations. (REPY-0006){bcolors.ENDC}")
diff --git a/restructuredpython/cload.py b/restructuredpython/cload.py
index f5481e1..5d3e069 100644
--- a/restructuredpython/cload.py
+++ b/restructuredpython/cload.py
@@ -20,7 +20,7 @@
import tomllib as toml
import time
from textformat import *
-
+from .predefined.subinterpreter.optimize import optimize_loop, optimize_function
def time_opening(func):
def wrapper(*args, **kwargs):
@@ -45,68 +45,14 @@ def wrapper(*args, **kwargs):
io_dylib = os.path.join(package_dir, "lib", "macos-libs", "io.dylib")
load_s = time.perf_counter()
-if sys.platform == "win32":
- if (struct.calcsize("P") * 8) == 32:
- lib = ctypes.WinDLL(io32_dll)
- else:
- lib = ctypes.WinDLL(io_dll)
-elif sys.platform == "darwin":
- lib = ctypes.CDLL(io_dylib)
-else:
- lib = ctypes.CDLL(io_so)
-
-
-def io_s():
- lib.check_file_exists.argtypes = [ctypes.c_char_p]
- lib.check_file_exists.restype = ctypes.c_int
-
- lib.read_file.argtypes = [ctypes.c_char_p]
- lib.read_file.restype = ctypes.c_wchar_p
-
- lib.write_file.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
- lib.write_file.restype = ctypes.c_int
-
- lib.read_binary_file.argtypes = [
- ctypes.c_char_p, ctypes.POINTER(
- ctypes.c_size_t)]
- lib.read_binary_file.restype = ctypes.POINTER(ctypes.c_char)
-
-
-io_s()
+import restructuredpython.api.libio as lib
load_e = time.perf_counter()
count = load_e - load_s
print(f"{bcolors.OKBLUE}Loading modules took {count}s{bcolors.ENDC}")
-
def load_toml_binary(filename):
- filename = str(filename)
- size = ctypes.c_size_t()
- raw_data_ptr = lib.read_binary_file(filename.encode(), ctypes.byref(size))
-
- if not raw_data_ptr:
- raise FileNotFoundError(
- f"{bcolors.BOLD}{bcolors.FAIL}Could not read {filename}{bcolors.ENDC}")
-
- raw_data = ctypes.string_at(raw_data_ptr, size.value)
+ raw_data = lib.read_binary_file(filename)
+ if raw_data is None:
+ raise FileNotFoundError(f"{bcolors.FAIL}Could not read {filename}{bcolors.ENDC}")
return toml.loads(raw_data.decode())
-
-
-def read_file_utf8(filename: str) -> str:
- size = ctypes.c_size_t()
- filename_bytes = filename.encode('utf-8')
-
- ptr = lib.read_binary_file(filename_bytes, ctypes.byref(size))
- if not ptr:
- raise FileNotFoundError(
- f"{bcolors.BOLD}{bcolors.FAIL}File not found: {filename}{bcolors.ENDC}")
-
- raw_bytes = ctypes.string_at(ptr, size.value)
-
- try:
- text = raw_bytes.decode('utf-8')
- except UnicodeDecodeError as e:
- raise UnicodeDecodeError(
- f"{bcolors.BOLD}{bcolors.FAIL}{e}{bcolors.ENDC}")
-
- return text
diff --git a/restructuredpython/include/io.c b/restructuredpython/include/io.c
deleted file mode 100644
index 826328b..0000000
--- a/restructuredpython/include/io.c
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2025 Rihaan Meher
-
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-// http://www.apache.org/licenses/LICENSE-2.0
-
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include
-#include
-#include
-#ifdef _WIN32
-#define EXPORT __declspec(dllexport)
-#else
-#define EXPORT __attribute__((visibility("default")))
-#endif
-
-EXPORT int check_file_exists(const char *filename) {
- FILE *file = fopen(filename, "r");
- if (file) {
- fclose(file);
- return 1;
- }
- return 0;
-}
-
-EXPORT char* read_file(const char *filename) {
- FILE *file = fopen(filename, "r");
- if (!file) return NULL;
-
- fseek(file, 0, SEEK_END);
- long size = ftell(file);
- rewind(file);
-
- char *buffer = (char*)malloc(size + 1);
- fread(buffer, size, 1, file);
- buffer[size] = '\0';
- fclose(file);
- return buffer;
-}
-
-EXPORT int write_file(const char *filename, const char *data) {
- FILE *file = fopen(filename, "w");
- if (!file) return 0;
-
- fputs(data, file);
- fclose(file);
- return 1;
-}
-
-EXPORT char* read_binary_file(const char *filename, size_t *size) {
- FILE *file = fopen(filename, "rb");
- if (!file) return NULL;
-
- fseek(file, 0, SEEK_END);
- *size = ftell(file);
- rewind(file);
-
- char *buffer = (char*)malloc(*size);
- fread(buffer, *size, 1, file);
- fclose(file);
-
- return buffer;
-}
\ No newline at end of file
diff --git a/restructuredpython/lib/DO_NOT_MODIFY_THIS_DIR.txt b/restructuredpython/lib/DO_NOT_MODIFY_THIS_DIR.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/restructuredpython/lib/io.c b/restructuredpython/lib/io.c
new file mode 100644
index 0000000..f0a2fc2
--- /dev/null
+++ b/restructuredpython/lib/io.c
@@ -0,0 +1,136 @@
+// # Copyright 2025 Rihaan Meher
+
+// # Licensed under the Apache License, Version 2.0 (the "License");
+// # you may not use this file except in compliance with the License.
+// # You may obtain a copy of the License at
+
+// # http://www.apache.org/licenses/LICENSE-2.0
+
+// # Unless required by applicable law or agreed to in writing, software
+// # distributed under the License is distributed on an "AS IS" BASIS,
+// # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// # See the License for the specific language governing permissions and
+// # limitations under the License.
+
+#define PY_SSIZE_T_CLEAN
+#include
+#include
+#include
+
+// Original C function declarations
+extern int check_file_exists(const char *filename);
+extern char* read_file(const char *filename);
+extern int write_file(const char *filename, const char *data);
+extern char* read_binary_file(const char *filename, size_t *size);
+
+int check_file_exists(const char *filename) {
+ FILE *file = fopen(filename, "r");
+ if (file) {
+ fclose(file);
+ return 1;
+ }
+ return 0;
+}
+
+char* read_file(const char *filename) {
+ FILE *file = fopen(filename, "r");
+ if (!file) return NULL;
+
+ fseek(file, 0, SEEK_END);
+ long size = ftell(file);
+ rewind(file);
+
+ char *buffer = (char*)malloc(size + 1);
+ fread(buffer, size, 1, file);
+ buffer[size] = '\0';
+ fclose(file);
+ return buffer;
+}
+
+int write_file(const char *filename, const char *data) {
+ FILE *file = fopen(filename, "w");
+ if (!file) return 0;
+
+ fputs(data, file);
+ fclose(file);
+ return 1;
+}
+
+char* read_binary_file(const char *filename, size_t *size) {
+ FILE *file = fopen(filename, "rb");
+ if (!file) return NULL;
+
+ fseek(file, 0, SEEK_END);
+ *size = ftell(file);
+ rewind(file);
+
+ char *buffer = (char*)malloc(*size);
+ fread(buffer, *size, 1, file);
+ fclose(file);
+ return buffer;
+}
+
+// Wrappers that expose C types but are valid PyObject*
+static PyObject* py_check_file_exists(PyObject *self, PyObject *args) {
+ const char* filename;
+ if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
+
+ int exists = check_file_exists(filename);
+ return PyLong_FromLong(exists);
+}
+
+static PyObject* py_read_file(PyObject *self, PyObject *args) {
+ const char* filename;
+ if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
+
+ char* result = read_file(filename);
+ if (!result) Py_RETURN_NONE;
+
+ PyObject* py_result = PyUnicode_FromString(result);
+ free(result);
+ return py_result;
+}
+
+static PyObject* py_write_file(PyObject *self, PyObject *args) {
+ const char* filename;
+ const char* data;
+ if (!PyArg_ParseTuple(args, "ss", &filename, &data)) return NULL;
+
+ int result = write_file(filename, data);
+ return PyLong_FromLong(result);
+}
+
+static PyObject* py_read_binary_file(PyObject *self, PyObject *args) {
+ const char* filename;
+ if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
+
+ size_t size = 0;
+ char* data = read_binary_file(filename, &size);
+ if (!data) Py_RETURN_NONE;
+
+ PyObject* result = PyBytes_FromStringAndSize(data, size);
+ free(data);
+ return result;
+}
+
+// Function table
+static PyMethodDef methods[] = {
+ {"check_file_exists", py_check_file_exists, METH_VARARGS, "Check if file exists"},
+ {"read_file", py_read_file, METH_VARARGS, "Read file contents"},
+ {"write_file", py_write_file, METH_VARARGS, "Write data to file"},
+ {"read_binary_file", py_read_binary_file, METH_VARARGS, "Read binary contents"},
+ {NULL, NULL, 0, NULL}
+};
+
+// Module definition
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "libio", // name of module
+ NULL, // module documentation
+ -1,
+ methods
+};
+
+PyMODINIT_FUNC PyInit_libio(void) {
+ return PyModule_Create(&moduledef);
+}
diff --git a/restructuredpython/parser.py b/restructuredpython/parser.py
index 825b92e..de520ee 100644
--- a/restructuredpython/parser.py
+++ b/restructuredpython/parser.py
@@ -1,5 +1,3 @@
-from .check_syntax import check_syntax
-import re
# Copyright 2025 Rihaan Meher
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,56 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from .check_syntax import check_syntax
+import re
+
+def wrap_loops_for_optimization(code):
+ """
+ Rewrites for/while loops with annotations into runtime functions
+ with decorators.
+ """
+ lines = code.splitlines()
+ modified_lines = []
+ i = 0
+ loop_counter = 0
+
+ while i < len(lines):
+ line = lines[i].strip()
+ if line.startswith("@optimize_loop("):
+ decorator_line = lines[i]
+ loop_line = lines[i + 1].strip()
+ loop_indent = len(lines[i + 1]) - len(loop_line)
+ func_name = f"_repy_optimized_loop_{loop_counter}"
+ loop_counter += 1
+
+ modified_lines.append(decorator_line)
+ modified_lines.append(" " * loop_indent + f"def {func_name}():")
+ modified_lines.append(" " * (loop_indent + 4) + loop_line)
+ i += 2
+
+ # Copy indented body lines until dedent or EOF
+ while i < len(lines):
+ body_line = lines[i]
+ if body_line.strip() == "":
+ modified_lines.append(body_line)
+ i += 1
+ continue
+ body_indent = len(body_line) - len(body_line.lstrip())
+ if body_indent <= loop_indent:
+ break
+ modified_lines.append(" " * (loop_indent + 8) + body_line.strip())
+ i += 1
+
+ modified_lines.append(" " * loop_indent + f"{func_name}()")
+ else:
+ modified_lines.append(lines[i])
+ i += 1
-def parse_repython(code):
+ return "\n".join(modified_lines)
+
+def parse_repython(code, mode="classic"):
"""Parses reStructuredPython and converts it to Python."""
+ required_imports = set()
def chain_pipeline(code):
parts = [part.strip() for part in code.split('|>')]
if len(parts) > 1:
@@ -25,12 +70,9 @@ def nest(parts):
return parts[0]
else:
return f'{parts[-1]}({nest(parts[:-1])})'
-
- variable, pipeline = parts[0].split(
- '=') if '=' in parts[0] else ('', parts[0])
+ variable, pipeline = parts[0].split('=') if '=' in parts[0] else ('', parts[0])
variable = variable.strip()
pipeline = pipeline.strip()
-
if variable:
nested_call = nest([pipeline] + parts[1:])
return f'{variable} = {nested_call}'
@@ -43,45 +85,83 @@ def nest(parts):
brace_stack = []
lines = code.splitlines()
- check_syntax(lines)
+ check_syntax(lines, mode=mode)
inside_comment_block = False
+ pending_optimize = None
+
+ for i, line in enumerate(lines):
+ stripped = line.strip()
+
+ # Detect directive
+ if stripped.startswith(""):
+ match = re.match(r'', stripped)
+ if match:
+ pending_optimize = match.group(1).strip()
+ continue
- for line in lines:
processed_line = chain_pipeline(line)
+ # Handle comment blocks
if inside_comment_block:
if processed_line.endswith("*/"):
modified_code.append(f"# {processed_line[:-2].strip()}")
inside_comment_block = False
else:
modified_code.append(f"# {processed_line.strip()}")
+ continue
elif processed_line.startswith("/*") and processed_line.endswith("*/"):
modified_code.append(f"# {processed_line[2:-2].strip()}")
+ continue
elif processed_line.startswith("/*"):
modified_code.append(f"# {processed_line[2:].strip()}")
inside_comment_block = True
+ continue
elif processed_line.endswith("*/"):
modified_code.append(f"# {processed_line[:-2].strip()}")
+ continue
+
+ # Apply decorator before next block
+ if pending_optimize:
+ if re.match(r'^\s*(for|while)\s+.*\{', processed_line):
+ modified_code.append(f"@optimize_loop({pending_optimize})")
+ required_imports.add("optimize_loop")
+ pending_optimize = None
+ elif re.match(r'^\s*def\s+.*\{', processed_line):
+ modified_code.append(f"@optimize_function({pending_optimize})")
+ required_imports.add("optimize_function")
+ pending_optimize = None
+
+ # Block conversions
+ if re.match(r'^\s*(if|for|while|def|try|elif|else|except|class|match|with|case)\s.*\{', processed_line):
+ modified_code.append(processed_line.split('{')[0] + ':')
+ brace_stack.append('{')
+ inside_block = True
+ elif re.match(r'^\s*\}', processed_line) and inside_block:
+ brace_stack.pop()
+ inside_block = len(brace_stack) > 0
+ elif re.match(r'^\s*match\(', processed_line):
+ modified_code.append(processed_line.split('{')[0] + ':')
+ brace_stack.append('{')
+ inside_block = True
+ elif re.match(r'^\s*case', processed_line):
+ modified_code.append(processed_line.split('{')[0] + ':')
+ brace_stack.append('{')
+ inside_block = True
else:
- if re.match(
- r'^\s*(if|for|while|def|try|elif|else|except|class|match|with|case)\s.*\{',
- processed_line):
- modified_code.append(processed_line.split('{')[0] + ':')
- brace_stack.append('{')
- inside_block = True
- elif re.match(r'^\s*\}', processed_line) and inside_block:
- brace_stack.pop()
- inside_block = len(brace_stack) > 0
- elif re.match(r'^\s*match\(', processed_line):
- modified_code.append(processed_line.split('{')[0] + ':')
- brace_stack.append('{')
- inside_block = True
- elif re.match(r'^\s*case', processed_line):
- modified_code.append(processed_line.split('{')[0] + ':')
- brace_stack.append('{')
- inside_block = True
- else:
- modified_code.append(processed_line)
+ modified_code.append(processed_line)
+
+ # Insert necessary imports at the top
+ import_lines = []
+ if "optimize_loop" in required_imports or "optimize_function" in required_imports:
+ imports = []
+ if "optimize_function" in required_imports:
+ imports.append("optimize_function")
+ if "optimize_loop" in required_imports:
+ imports.append("optimize_loop")
+ import_lines.append(f"from restructuredpython.predefined.subinterpreter import {', '.join(imports)}")
+
+ raw_code = '\n'.join(import_lines + modified_code)
+ final_code = wrap_loops_for_optimization(raw_code)
+ return final_code
- return '\n'.join(modified_code)
diff --git a/restructuredpython/predefined/subinterpreter/__init__.py b/restructuredpython/predefined/subinterpreter/__init__.py
new file mode 100644
index 0000000..5c5dc7e
--- /dev/null
+++ b/restructuredpython/predefined/subinterpreter/__init__.py
@@ -0,0 +1,9 @@
+from .optimize import (
+ optimize_function,
+ optimize_loop
+)
+
+__all__ = [
+ "optimize_function",
+ "optimize_loop"
+]
\ No newline at end of file
diff --git a/restructuredpython/predefined/subinterpreter/optimize.py b/restructuredpython/predefined/subinterpreter/optimize.py
new file mode 100644
index 0000000..228fb7b
--- /dev/null
+++ b/restructuredpython/predefined/subinterpreter/optimize.py
@@ -0,0 +1,65 @@
+# Copyright 2025 Rihaan Meher
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import gc, time, sys, functools, types, dis, multiprocessing
+
+def optimize_loop(profile=False, gct=False, parallel=False, unroll=0):
+ def decorator(fn):
+ @functools.wraps(fn)
+ def wrapper(*args, **kwargs):
+ # Garbage Collection
+ if gct:
+ gc.collect()
+
+ # Profiling
+ start = time.perf_counter() if profile else None
+
+ # Execute loop
+ if parallel:
+ # Naive parallelism: assuming fn yields or returns a list
+ results = fn(*args, **kwargs)
+ with multiprocessing.Pool() as pool:
+ pool.map(lambda x: x, results)
+ else:
+ fn(*args, **kwargs)
+
+ if profile:
+ duration = time.perf_counter() - start
+ print(f"[PROFILE] Loop took {duration:.4f}s")
+
+ return wrapper
+ return decorator
+
+def optimize_function(profile=False, trace=False):
+ def decorator(fn):
+ if profile:
+ @functools.wraps(fn)
+ def profiled(*args, **kwargs):
+ start = time.perf_counter()
+ result = fn(*args, **kwargs)
+ print(f"[PROFILE] {fn.__name__} took {time.perf_counter() - start:.4f}s")
+ return result
+ return profiled
+ if trace:
+ def tracer(frame, event, arg):
+ print(f"[TRACE] {event} in {frame.f_code.co_name}")
+ return tracer
+ def wrapped(*args, **kwargs):
+ sys.settrace(tracer)
+ result = fn(*args, **kwargs)
+ sys.settrace(None)
+ return result
+ return wrapped
+ return fn
+ return decorator
diff --git a/restructuredpython/restructuredpython.py b/restructuredpython/restructuredpython.py
index b6abc9a..d9e3ea6 100644
--- a/restructuredpython/restructuredpython.py
+++ b/restructuredpython/restructuredpython.py
@@ -27,15 +27,15 @@
from textformat import *
-def compile_header_file(header_filename):
+def compile_header_file(header_filename, mode="classic"):
"""Compiles a .cdata file and returns the corresponding Python code."""
header_filename = Path(header_filename).resolve()
header_filename = str(header_filename)
- if lib.check_file_exists(header_filename.encode()) == 0:
+ if lib.check_file_exists(header_filename) == 0:
raise FileNotFoundError(
f"{bcolors.BOLD}{bcolors.FAIL}Header file {header_filename} not found.{bcolors.ENDC}")
try:
- header_code = read_file_utf8(header_filename)
+ header_code = lib.read_file(header_filename)
if not header_code.strip():
raise ValueError(
f"{bcolors.BOLD}{bcolors.FAIL}Header file {header_filename} is empty.{bcolors.ENDC}")
@@ -44,13 +44,13 @@ def compile_header_file(header_filename):
f"{bcolors.WARNING}Error opening file {header_filename}: {e}{bcolors.ENDC}")
return ""
- return parse_repython(header_code)
+ return parse_repython(header_code, mode)
PREDEFINED_HEADERS_DIR = os.path.join(os.path.dirname(__file__), "predefined")
-def process_includes(code, input_file):
+def process_includes(code, input_file, mode="classic"):
"""Processes #include directives, handling both predefined and user-defined files."""
include_pattern = r'\s*include\s+[\'"]([^\'"]+)[\'"]'
includes = re.findall(include_pattern, code)
@@ -62,7 +62,7 @@ def process_includes(code, input_file):
predefined_path = os.path.join(
PREDEFINED_HEADERS_DIR, include.replace(
'.', os.sep) + '.py')
- if lib.check_file_exists(predefined_path.encode()):
+ if lib.check_file_exists(predefined_path):
header_code += compile_header_file(predefined_path) + "\n"
continue
# userdefined
@@ -73,8 +73,8 @@ def process_includes(code, input_file):
os.path.abspath(input_file)),
include)
- if lib.check_file_exists(include.encode()):
- header_code += compile_header_file(include) + "\n"
+ if lib.check_file_exists(include):
+ header_code += compile_header_file(include, mode) + "\n"
else:
print(
f"{
@@ -97,7 +97,7 @@ def main():
input_file = str(input_file)
- if lib.check_file_exists(input_file.encode()) == 0:
+ if lib.check_file_exists(input_file) == 0:
print(
f"{
bcolors.BOLD}{
@@ -131,7 +131,7 @@ def main():
matching_files.append(file_path_temp)
for file_path_z in matching_files:
file_path_z = str(file_path_z)
- source_code_z = lib.read_file(file_path_z.encode()).decode()
+ source_code_z = lib.read_file(file_path_z)
header_code_z, code_without_includes_z = process_includes(
source_code_z, file_path_z)
@@ -142,7 +142,7 @@ def main():
output_file_z = os.path.splitext(file_path_z)[0] + '.py'
- lib.write_file(output_file_z.encode(), final_code_z.encode())
+ lib.write_file(output_file_z, final_code_z)
print(
f"{bcolors.OKGREEN}Compiled {file_path_z} to {output_file_z}{bcolors.ENDC}")
@@ -159,7 +159,7 @@ def main():
output_file = os.path.splitext(input_file)[0] + '.py'
- lib.write_file(output_file.encode(), final_code.encode())
+ lib.write_file(output_file, final_code)
print(
f"{
@@ -178,7 +178,7 @@ def launch():
input_file = args.filename
input_file = str(input_file)
- if lib.check_file_exists(input_file.encode()) == 0:
+ if lib.check_file_exists(input_file) == 0:
print(
f"{
bcolors.BOLD}{
@@ -190,9 +190,9 @@ def launch():
source_code = f.read()
header_code, code_without_includes = process_includes(
- source_code, input_file)
+ source_code, input_file, mode="launch")
- python_code = parse_repython(code_without_includes)
+ python_code = parse_repython(code_without_includes, mode="launch")
final_code = header_code + python_code
diff --git a/restructuredpython/tempload.py b/restructuredpython/tempload.py
index 81e1654..e46b351 100644
--- a/restructuredpython/tempload.py
+++ b/restructuredpython/tempload.py
@@ -12,22 +12,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from .cload import lib
+from .cload import lib, optimize_function, optimize_loop
from textformat import bcolors
import tempfile
import os
+exec_globals = {
+ "__name__": "__main__"
+}
def execute_code_temporarily(code):
"""Executes the compiled python code"""
with tempfile.TemporaryDirectory() as tmpdir:
- temp_file_path = os.path.join(tmpdir, "compiled_repy.py")
- lib.write_file(temp_file_path.encode(), code.encode())
+ temp_file_path = os.path.join(tmpdir, "_runtime.rpyt")
+ lib.write_file(temp_file_path, code)
try:
- exec(open(temp_file_path).read(), {"__name__": "__main__"})
+ exec(open(temp_file_path).read(), exec_globals)
except Exception as e:
print(f"{bcolors.FAIL}Error during execution: {e}")
- print(
- f"You can view the generated file at {
- (temp_file_path)}{
- bcolors.ENDC}")
diff --git a/tests/.repy/ops.py b/tests/.repy/ops.py
new file mode 100644
index 0000000..6842b80
--- /dev/null
+++ b/tests/.repy/ops.py
@@ -0,0 +1,14 @@
+from restructuredpython.predefined.subinterpreter import optimize_loop
+print("Running unoptimized loop:")
+import time
+start = time.perf_counter()
+for i in range(10_000_000) :
+ temp = str(i) * 10
+end = time.perf_counter()
+print("Unoptimized loop time:", round(end - start, 4), "seconds")
+
+@optimize_loop(gct=True, profile=True)
+def _repy_optimized_loop_0():
+ for j in range(10_000_000) :
+ temp = str(j) * 10
+_repy_optimized_loop_0()
\ No newline at end of file
diff --git a/tests/.repy/ops.repy b/tests/.repy/ops.repy
new file mode 100644
index 0000000..347aa10
--- /dev/null
+++ b/tests/.repy/ops.repy
@@ -0,0 +1,13 @@
+print("Running unoptimized loop:")
+import time
+start = time.perf_counter()
+for i in range(10_000_000) {
+ temp = str(i) * 10
+}
+end = time.perf_counter()
+print("Unoptimized loop time:", round(end - start, 4), "seconds")
+
+
+for j in range(10_000_000) {
+ temp = str(j) * 10
+}