Compare commits

..

199 Commits

Author SHA1 Message Date
William Bell
2d988a5120 remove upgrade 2025-11-30 05:56:45 +00:00
William Bell
3d92071d0a fix upgrade 2025-11-30 05:56:30 +00:00
William Bell
357c8745a4 fix dependancies 2025-11-30 05:55:40 +00:00
William Bell
4101144e26 test 2025-11-30 05:50:34 +00:00
William Bell
6a32c4721c update readme to have build instructions 2025-11-30 05:33:20 +00:00
William Bell
6de89ebb2f test 2025-11-30 05:26:10 +00:00
William Bell
4d4749c65e test 2025-11-30 05:24:24 +00:00
William Bell
916d94b32b test 2025-11-30 04:31:32 +00:00
e3108b2606 Merge branch 'main' of https://github.com/Open-Argon/Chloride 2025-11-26 03:07:22 +00:00
f3912ae49f add item access 2025-11-26 03:07:06 +00:00
William Bell
9de85f3b72 change logo colours to match C 2025-11-21 01:06:59 +00:00
William Bell
41a6fb17da Merge branch 'main' of https://github.com/Open-Argon/Carbon 2025-11-21 01:05:28 +00:00
William Bell
7a48771976 add logos 2025-11-21 01:05:04 +00:00
William Bell
89abf4e036 Update README.md 2025-11-21 01:04:51 +00:00
William Bell
df409dd3f6 Update README.md 2025-11-21 00:30:57 +00:00
William Bell
646938ea79 Update README.md 2025-11-21 00:21:36 +00:00
William Bell
9befc3760a Merge branch 'main' of https://github.com/Open-Argon/Carbon 2025-11-20 23:54:54 +00:00
William Bell
3d2ba09518 change back to stack level registers on call 2025-11-20 23:54:35 +00:00
94b86fc416 change the tests 2025-11-12 11:29:48 +00:00
William Bell
0a2aa7369f fix memory leak that occures when converting a hashmap to a string in debug mode 2025-11-11 19:57:24 +00:00
William Bell
0b594d7882 revert test 2025-11-11 18:06:54 +00:00
William Bell
c0ba18c37e fix buffer overflow in hashmap to array function. 2025-11-11 03:11:09 +00:00
William Bell
608fd86003 fix memory bug occuring in debug mode and attempting to fix another 2025-11-11 02:30:14 +00:00
William Bell
434b0ed99e fix bug where it hashmap output bug 2025-11-11 02:00:17 +00:00
William Bell
bfaf8df0d0 attempt to remove redundent memory allocations 2025-11-08 04:29:09 +00:00
William Bell
3e3df5595e fix hashmap to list missing items when they are in the same position in the list 2025-11-04 18:10:19 +00:00
William Bell
51c6bdcea9 fix seg fault in dictionary creation 2025-10-22 20:33:01 +01:00
William Bell
dd3b3b936d add dictionaries 2025-10-22 19:53:19 +01:00
William Bell
b6714b390a fix seg fault when callng a function with not enough parameters 2025-10-22 03:52:47 +01:00
William Bell
a9b1d23f79 fix windows build 2025-10-21 21:43:02 +01:00
William Bell
6d3e79b731 fix window build 2025-10-21 21:32:02 +01:00
William Bell
b3ee64d294 fix windows build 2025-10-21 21:08:27 +01:00
William Bell
e6ec0fa38a fix windows building 2025-10-21 20:57:22 +01:00
William Bell
c8394228b3 add function assignment 2025-10-21 20:34:33 +01:00
70ba81bebc change to __set_attr__ 2025-09-19 00:31:04 +01:00
William Bell
50ff9fbefc add __setattr__ 2025-09-17 22:56:44 +01:00
William Bell
042c278b8d Merge remote-tracking branch 'refs/remotes/origin/main' 2025-09-17 17:26:41 +01:00
William Bell
81efaaac07 fix path bug 2025-09-17 17:25:42 +01:00
3b0ec79955 start adding set attribute support 2025-09-17 17:24:50 +01:00
William Bell
4be8e8e32f add __repr__ 2025-09-13 01:17:16 +01:00
William Bell
5846adf025 add dictionary string 2025-09-13 01:01:35 +01:00
William Bell
daa8056b7a add license to shell 2025-09-12 01:21:08 +01:00
William Bell
1a5abd9543 impliment micro optimisations by reordering and restructing the structs so they are smaller. 2025-09-09 18:41:19 +01:00
William Bell
774890de1d change the built in slots to be allocated on the fly, making the objects smaller but faster 2025-09-09 17:55:54 +01:00
William Bell
fc7cfc7cfb change how access is done and add built in array (need to optimise the size) 2025-09-09 06:24:23 +01:00
William Bell
d46a6dc209 improve performance by using an inline locals array in hashmaps 2025-09-08 02:21:26 +01:00
William Bell
23c4a7ebd1 add not and or, while also improving performance. 2025-09-07 21:03:57 +01:00
William Bell
57728af0b6 add multiplication, division, and && 2025-09-03 05:21:41 +01:00
William Bell
df040adf45 get functions to use a new register assignment, since they get new registers now 2025-09-02 22:31:01 +01:00
William Bell
c2e0cdc6d6 fix buffer overflow seg fault when using cache 2025-09-02 18:35:43 +01:00
William Bell
571efe46b7 fix buffer overflow seg fault when using cache 2025-09-02 18:35:36 +01:00
William Bell
67569bffc2 shitty boehm is dereferencing 0x20 for some stupid reason 2025-09-02 05:06:48 +01:00
William Bell
f5ee0f6fc8 fix operations not performing correctly and trying to fix cached code not executing correctly 2025-09-02 02:59:47 +01:00
William Bell
fd5b237dfe set up so reusing scope when in a loop 2025-09-01 23:09:09 +01:00
William Bell
322716af0c remove debug print 2025-09-01 22:11:54 +01:00
William Bell
c67b37d8b2 remove performance spec 2025-09-01 21:51:49 +01:00
William Bell
b9c0503d54 keep loop using the same dispatch table, removing the need to recreate the dispatch table 2025-09-01 21:51:16 +01:00
William Bell
19268f3070 improve performance massively from 0.9 seconds to 0.38 seconds :) 2025-09-01 20:25:47 +01:00
William Bell
4f91bf48f3 improve performance for integers 2025-08-30 03:29:02 +01:00
William Bell
4fc28d3b76 fix seg fault in optimised builds 2025-08-29 13:42:21 +01:00
c01dee80b0 add bool value to speed up primitives 2025-08-29 12:58:02 +01:00
0f0a3f5d31 change to dispatch table to hopefully improve speed 2025-08-29 12:22:35 +01:00
William Bell
f598c215e7 start adding assignment (currently only identifier assignment works) 2025-08-29 01:41:53 +01:00
William Bell
fff4f6bcb5 add while loop 2025-08-28 04:07:19 +01:00
William Bell
c322d5680f fix double free 2025-08-27 16:16:32 +01:00
William Bell
db650d8ccf add anonymous functions 2025-08-26 02:13:48 +01:00
William Bell
6ad0b2c02e switch allocations to atomic to improve performance 2025-08-20 00:26:35 +01:00
William Bell
624a54c90c remove gmp-x86_64.h 2025-08-19 02:41:41 +01:00
William Bell
c856e7d654 add multiplication and division 2025-08-19 02:36:09 +01:00
William Bell
a96023ced1 fix for winblows 2025-08-18 15:03:11 +01:00
William Bell
1908d9bbbb fix for winblows 2025-08-18 14:43:49 +01:00
William Bell
47db2ca27d fix for winblows 2025-08-18 06:40:59 +01:00
William Bell
2e7b3b4baa fix for winblows 2025-08-18 06:38:30 +01:00
William Bell
24163e3389 fix gmp bug 2025-08-18 06:25:29 +01:00
William Bell
0c0832d131 add shell and stdin piping support 2025-08-18 06:22:13 +01:00
William Bell
1742a0c52d add shell and stdin piping support 2025-08-18 06:22:00 +01:00
William Bell
224039ba43 fix arch name 2025-08-17 01:30:18 +01:00
William Bell
5e7ce495e4 fix runner 2025-08-17 01:12:52 +01:00
William Bell
35a0f35cf8 add native arm support 2025-08-17 00:49:34 +01:00
William Bell
f9490ceac0 bloody ai 2025-08-16 18:28:50 +01:00
William Bell
4cda311008 bloody ai 2025-08-16 18:25:46 +01:00
William Bell
b3aa653076 incorrect environment variable assignment 2025-08-16 18:20:12 +01:00
William Bell
fc3321bcf0 incorrect package name 2025-08-16 18:18:00 +01:00
William Bell
868b3bfc3d change to cross compile linux 2025-08-16 18:15:32 +01:00
William Bell
f5e241aba0 forgot to add cmake and make 2025-08-16 16:08:06 +01:00
William Bell
8c3ee3fe05 fix --break-system-packages 2025-08-16 15:42:34 +01:00
William Bell
eb285b6e8f add linux arm64 to builds and reshape how execution is done. 2025-08-16 15:25:33 +01:00
William Bell
78a1edd572 add calculation to test 2025-08-16 05:40:29 +01:00
William Bell
b905026010 fix rosetta not used 2025-08-16 04:31:21 +01:00
William Bell
677afd9433 fix using Rosetta 2025-08-16 04:10:57 +01:00
William Bell
757da3f973 stupid ai 2025-08-16 03:51:05 +01:00
William Bell
5a86510c3b fix release for macos x86_64 and arm64 2025-08-16 03:48:48 +01:00
William Bell
fb8b6a89ae build for more architectures 2025-08-16 03:41:32 +01:00
William Bell
6ddf9953e7 change windows builds to tar.gz 2025-08-16 03:23:01 +01:00
William Bell
1609227a42 add bcrypt for windows 2025-08-16 03:10:50 +01:00
William Bell
51f6a88ce8 add profile to build 2025-08-16 03:00:01 +01:00
William Bell
f420273471 fix backslashes 2025-08-16 02:46:33 +01:00
William Bell
4b2a747338 use msys/flex 2025-08-16 02:36:47 +01:00
William Bell
5277814af0 fix conan 2025-08-16 02:31:15 +01:00
William Bell
8928ab2d99 add cmake as dependency 2025-08-16 02:20:57 +01:00
William Bell
d08b307c6e add python as a dependency 2025-08-16 02:12:55 +01:00
William Bell
6474329afc switch to conan for windows 2025-08-16 02:08:56 +01:00
William Bell
c49e67c839 switch windows to use conan 2025-08-16 02:04:00 +01:00
William Bell
25cb96e473 try get it to be static 2025-08-16 01:57:56 +01:00
William Bell
f11890a8b3 fix linking for linux and macos 2025-08-16 01:39:44 +01:00
William Bell
59b1d222c2 fix cmake 2025-08-16 01:32:57 +01:00
William Bell
2fba132016 make gc and gmp static and math dynamic 2025-08-16 01:22:08 +01:00
William Bell
bddc2cdc79 fix release to merge multiple 2025-08-16 01:06:06 +01:00
William Bell
e1b80b42d9 fix make release 2025-08-16 01:02:48 +01:00
William Bell
dab86925b4 fix winblows 2025-08-16 00:58:56 +01:00
William Bell
0f45052dce fix for winblows 2025-08-16 00:56:35 +01:00
William Bell
68f4207216 fix for winblows 2025-08-16 00:54:33 +01:00
William Bell
f9f8ca08c6 fix bug for windows 2025-08-16 00:50:23 +01:00
William Bell
0666b02c13 fix flex tool 2025-08-16 00:44:00 +01:00
William Bell
1654507835 fix for windows 2025-08-16 00:42:13 +01:00
William Bell
d054ece8e2 release 2025-08-16 00:39:37 +01:00
William Bell
4937942d6e fix release 2025-08-16 00:35:48 +01:00
William Bell
82ea92183f fix release 2025-08-16 00:28:08 +01:00
William Bell
5fb15b476f fix release 2025-08-16 00:26:26 +01:00
William Bell
d1a455dbbe fix release.yml 2025-08-16 00:07:10 +01:00
William Bell
a81640747d fix release.yml 2025-08-15 22:07:25 +01:00
William Bell
4a1ed23f96 fix release.yml 2025-08-15 22:05:57 +01:00
William Bell
eb36d02fcb fix release.yml 2025-08-15 22:03:23 +01:00
William Bell
7b3a1e1835 fix release.yml 2025-08-15 21:52:16 +01:00
William Bell
8e53579682 fix release.yml 2025-08-15 21:36:51 +01:00
William Bell
0d8f262185 this thing is really annoying me now 2025-08-15 21:34:31 +01:00
William Bell
fc6f41d89b fix release.yml 2025-08-15 21:30:01 +01:00
William Bell
6a7ce72eb7 fix cmake 2025-08-15 21:23:08 +01:00
William Bell
f84e5429a5 fix release.yml 2025-08-15 21:16:48 +01:00
William Bell
f4c7294267 fix release.yml 2025-08-15 21:14:17 +01:00
William Bell
be4b04a286 fix release.yml 2025-08-15 20:59:49 +01:00
William Bell
9d11122e93 fix conanfile.py 2025-08-15 20:50:58 +01:00
William Bell
241e447da0 fix release.yml 2025-08-15 20:30:54 +01:00
William Bell
dd750ab164 fix release.yml 2025-08-15 20:26:54 +01:00
William Bell
922b129250 fix release.yml 2025-08-15 20:18:17 +01:00
William Bell
c2df9c0e83 fix release.yml 2025-08-15 20:15:18 +01:00
William Bell
923503493e fix release.yml 2025-08-15 20:04:55 +01:00
William Bell
686cb08f11 fix conan file 2025-08-15 19:56:54 +01:00
William Bell
1cfb4acda6 fix CMakeLists.txt 2025-08-15 19:52:33 +01:00
William Bell
436f30330b fix copying license 2025-08-15 19:45:12 +01:00
William Bell
5381967ed6 fix conanfile 2025-08-15 19:40:41 +01:00
William Bell
6f84a4a485 fix conan file 2025-08-15 19:37:38 +01:00
William Bell
4b4b1fa777 fix release.yml 2025-08-15 19:22:26 +01:00
William Bell
2b6e785638 fix conan file 2025-08-15 19:19:15 +01:00
William Bell
51e82e5b2e fix release.yml 2025-08-15 19:15:28 +01:00
William Bell
2c56810cc4 change release.yml 2025-08-15 19:13:49 +01:00
William Bell
663797d1fb change workflow to support other plateforms 2025-08-15 19:06:00 +01:00
William Bell
ed1b77a78e fix unused parameters 2025-08-15 05:43:08 +01:00
William Bell
5d81045dad Merge remote-tracking branch 'refs/remotes/origin/main' 2025-08-15 05:42:04 +01:00
William Bell
2d577594fc add subtract support and string concatenation 2025-08-15 05:41:26 +01:00
413725080b fix for macos 2025-08-14 16:20:52 +01:00
William Bell
c3c7f1597e fix numbers points 2025-08-14 05:44:55 +01:00
William Bell
4b439fc52a change function depending on the operation 2025-08-14 05:42:38 +01:00
William Bell
340843c99c start working on supporting operations 2025-08-14 04:51:11 +01:00
William Bell
d4528e44f6 change how numbers are stored so they are in an efficent binary format, able to be quickly read by the runtime 2025-08-12 00:13:01 +01:00
William Bell
f851b37f99 work on number parsing 2025-08-11 19:26:19 +01:00
William Bell
d2e742f992 add number type and object 2025-08-11 01:41:44 +01:00
William Bell
bbf8794dd5 fix scope bug in if statement 2025-08-10 22:14:06 +01:00
William Bell
c71375c7a4 fix memory being freed too early 2025-08-10 04:39:50 +01:00
49b1c1858a turn access into a function to be ran at runtime 2025-08-10 01:45:46 +01:00
ad3e31b0a2 have memory malloced then converted to GC 2025-08-09 22:11:59 +01:00
b755e574bd add string initialisation 2025-08-09 18:51:23 +01:00
William Bell
345c4ce841 make objects initialisation through type.__call__ 2025-08-09 17:00:57 +01:00
William Bell
0635ba8517 work on method wrapper and native function support 2025-08-09 06:40:16 +01:00
William Bell
38e2cad507 pass object into call if object is a method 2025-08-07 05:16:51 +01:00
William Bell
4b6d15336a make native function support and start working on support for error catching 2025-08-06 22:31:31 +01:00
William Bell
c567b59459 add __call__ support 2025-08-06 03:03:06 +01:00
William Bell
8ba755aeac break stack frames into chunks 2025-08-05 05:11:09 +01:00
c3c41e0336 fix incorrect formats and output memory usage on call stack warning 2025-08-05 01:00:07 +01:00
William Bell
a8acafffe9 add function calling 2025-08-04 23:31:25 +01:00
6c05eff6a4 Merge branch 'main' of https://github.com/Open-Argon/Chloride 2025-08-04 02:13:37 +01:00
2ba60b38ae fix for macos 2025-08-04 02:13:34 +01:00
af371f5b9f start working on function calls 2025-08-04 02:09:38 +01:00
417d66faf3 write runtime object bootstrap 2025-08-03 01:48:41 +01:00
William Bell
a7d7ded803 start working on runtime oop 2025-08-02 20:17:24 +01:00
8ea69cce67 return err in translator 2025-07-14 22:22:26 +01:00
0c8d018238 add jump for else statement 2025-07-14 19:50:44 +01:00
1f34490165 fix memory leak in return 2025-07-14 15:22:57 +01:00
ef5edfa13a fix licensing 2025-07-14 05:46:54 +01:00
e519cc38ab pull changes from libdye 2025-07-14 05:34:43 +01:00
f1e8ad1ac2 add return 2025-07-14 05:33:57 +01:00
1bdc792705 translate and execute do wraps 2025-07-14 04:51:00 +01:00
217e4047d3 fix lexer and argon license comments 2025-07-13 19:06:02 +01:00
c3e9a09dee re add license.txt for github 2025-07-13 18:33:50 +01:00
f5103cb6a3 follow reuse spec for license 2025-07-13 18:28:05 +01:00
f7ff3393f0 add if statement and declaration 2025-07-13 03:34:31 +01:00
744e3c281d remove license header 2025-07-12 03:37:06 +01:00
c0eb9e3a04 add hashmap to scope and identifier loading at runtime 2025-07-12 03:33:59 +01:00
fe7eaa8de3 fix some memory leaks 2025-07-09 14:47:16 +01:00
66b44e8f3a add full return err support in parser 2025-07-09 14:34:00 +01:00
0cb55fc563 move assign to return errors 2025-07-09 05:09:12 +01:00
c4731597f3 start rewriting the parser to return with error messages so errors can be caught 2025-07-09 04:58:49 +01:00
e234ea074b start adding error message support 2025-07-09 01:55:40 +01:00
9e5e932d39 start adding error message support 2025-07-09 01:55:32 +01:00
fba074a5a4 limit arguments to not support duplicate names 2025-07-08 04:31:01 +01:00
72cc87f5b6 create executable function which identifies and loads a cache if available 2025-07-07 04:03:11 +01:00
5c0ced5e45 start supporting identifiers in bytecode 2025-07-06 03:19:30 +01:00
886599c9c5 change to use cwalk for paths 2025-07-05 23:56:54 +01:00
cbebe4812b pull submodules 2025-07-05 04:58:08 +01:00
171 changed files with 11929 additions and 2378 deletions

View File

@@ -1,19 +1,26 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
name: Build and Release name: Build and Release
on: on:
push: push:
tags: tags:
- '*' # Trigger on any tag push - '*' # Any tag
jobs: jobs:
build_and_release: build-linux-x86_64:
runs-on: ubuntu-latest runs-on: ubuntu-latest # build both architectures
steps: steps:
- name: Checkout code - uses: actions/checkout@v3
uses: actions/checkout@v3 with:
submodules: recursive
- name: Setup Python (needed for Conan) - name: Install build tools
run: sudo apt-get update && sudo apt-get install -y flex bison
- name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: '3.x' python-version: '3.x'
@@ -22,44 +29,210 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install conan pip install conan
- name: Configure Conan
run: |
conan profile detect conan profile detect
- name: Install dependencies and build with Conan - name: Build
run: | run: |
conan install . --build=missing conan install . --build=missing
conan build . conan build .
- name: Determine if prerelease
id: prerelease_check - name: Package
run: |
TAG=${GITHUB_REF##refs/tags/}
if [[ "$TAG" == prerelease-* ]]; then
echo "true" > prerelease.txt
else
echo "false" > prerelease.txt
fi
echo "prerelease=$(cat prerelease.txt)" >> $GITHUB_OUTPUT
- name: Archive build folder
run: | run: |
TAG=${GITHUB_REF##refs/tags/} TAG=${GITHUB_REF##refs/tags/}
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m) ARCH=$(uname -m)
FOLDER_NAME="chloride-$TAG-linux-${ARCH}" FOLDER="chloride-$TAG-$OS-$ARCH"
TAR_NAME="$FOLDER_NAME.tar.gz" TAR="$FOLDER.tar.gz"
mv build/bin "$FOLDER_NAME" mv build/bin "$FOLDER"
cp LICENSE "$FOLDER_NAME" cp LICENSE.txt "$FOLDER"
tar -czf "$TAR_NAME" "$FOLDER_NAME" tar -czf "$TAR" "$FOLDER"
echo "TAR_NAME=$TAR_NAME" >> $GITHUB_ENV echo "TAR_NAME=$TAR" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: linux-x86_64-artifact
path: ${{ env.TAR_NAME }}
build-linux-arm64:
runs-on: ubuntu-22.04-arm # build both architectures
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install build tools
run: sudo apt-get update && sudo apt-get install -y flex bison
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install Conan
run: |
python -m pip install --upgrade pip
pip install conan
conan profile detect
- name: Build
run: |
conan install . --build=missing
conan build .
- name: Package
run: |
TAG=${GITHUB_REF##refs/tags/}
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
FOLDER="chloride-$TAG-$OS-$ARCH"
TAR="$FOLDER.tar.gz"
mv build/bin "$FOLDER"
cp LICENSE.txt "$FOLDER"
tar -czf "$TAR" "$FOLDER"
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: linux-arm64-artifact
path: ${{ env.TAR_NAME }}
build-macos:
runs-on: macos-latest
strategy:
matrix:
arch: [x86_64, arm64] # build both architectures
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install build tools
run: brew install flex bison
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install Conan
run: |
python -m pip install --upgrade pip
pip install conan
if [ "${{ matrix.arch }}" = "x86_64" ] && [ "$(uname -m)" = "arm64" ]; then
arch -x86_64 conan profile detect
else
conan profile detect
fi
- name: Build
run: |
BUILD_DIR="build_${{ matrix.arch }}"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# Use Rosetta for x86_64 builds on Apple Silicon
if [ "${{ matrix.arch }}" = "x86_64" ] && [ "$(uname -m)" = "arm64" ]; then
arch -x86_64 bash -c "
export CMAKE_OSX_ARCHITECTURES=x86_64
conan install .. --build=missing
conan build ..
"
else
export CMAKE_OSX_ARCHITECTURES="${{ matrix.arch }}"
conan install .. --build=missing
conan build ..
fi
cd ..
- name: Package
run: |
TAG=${GITHUB_REF##refs/tags/}
OS="macos"
ARCH="${{ matrix.arch }}"
FOLDER="chloride-$TAG-$OS-$ARCH"
TAR="$FOLDER.tar.gz"
mv build/bin "$FOLDER"
cp LICENSE.txt "$FOLDER"
tar -czf "$TAR" "$FOLDER"
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: macos-${{ matrix.arch }}-artifact
path: ${{ env.TAR_NAME }}
build-windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: >
base-devel
mingw-w64-x86_64-gcc
mingw-w64-x86_64-make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-python
mingw-w64-x86_64-python-pip
msys/flex
- name: Install Conan
run: |
python -m pip install --upgrade pip
pip install conan
conan profile detect
- name: Build Project
run: |
conan install . --profile windows-profile.txt --build=missing
conan build . --profile windows-profile.txt
- name: Package
run: |
TAG=${GITHUB_REF##refs/tags/}
OS="windows"
ARCH=$(uname -m)
FOLDER="chloride-$TAG-$OS-$ARCH"
TAR="$FOLDER.tar.gz"
mv build/bin "$FOLDER"
cp LICENSE.txt "$FOLDER"
tar -czf "$TAR" "$FOLDER"
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: windows-artifact
path: ${{ env.TAR_NAME }}
release:
runs-on: ubuntu-latest
needs: [build-linux-x86_64, build-linux-arm64, build-macos, build-windows]
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
merge-multiple: true
- name: Create GitHub Release - name: Create GitHub Release
id: create_release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
with: with:
tag: ${{ github.ref_name }} tag: ${{ github.ref_name }}
name: Release ${{ github.ref_name }} name: Release ${{ github.ref_name }}
body: | body: Automated release based on tag ${{ github.ref_name }}
Automated release based on tag ${{ github.ref_name }}
draft: false draft: false
prerelease: ${{ steps.prerelease_check.outputs.prerelease }} prerelease: ${{ startsWith(github.ref_name, 'prerelease-') }}
artifacts: ${{ env.TAR_NAME }} artifacts: "./artifacts/*"

8
.gitignore vendored
View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
# Prerequisites # Prerequisites
*.d *.d
@@ -60,6 +64,6 @@ build
*.yy.c *.yy.c
*.yy.h *.yy.h
out.arbin __isotope__
rand_test.ar
__arcache__ __arcache__
argon_modules

13
.gitmodules vendored
View File

@@ -1,3 +1,16 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
[submodule "external/xxhash"] [submodule "external/xxhash"]
path = external/xxhash path = external/xxhash
url = https://github.com/Cyan4973/xxHash.git url = https://github.com/Cyan4973/xxHash.git
[submodule "external/cwalk"]
path = external/cwalk
url = https://github.com/likle/cwalk.git
[submodule "external/libdye"]
path = external/libdye
url = https://github.com/Ugric/libdye.git
[submodule "external/linenoise"]
path = external/linenoise
url = https://github.com/antirez/linenoise

3
.vscode/c_cpp_properties.json.license vendored Normal file
View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 William Bell
SPDX-License-Identifier: GPL-3.0-or-later

2
.vscode/launch.json vendored
View File

@@ -9,7 +9,7 @@
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/bin/argon", "program": "${workspaceFolder}/bin/argon",
"args": ["test.ar"], "args": [],
"stopAtEntry": true, "stopAtEntry": true,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"environment": [], "environment": [],

3
.vscode/launch.json.license vendored Normal file
View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 William Bell
SPDX-License-Identifier: GPL-3.0-or-later

3
.vscode/settings.json.license vendored Normal file
View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 William Bell
SPDX-License-Identifier: GPL-3.0-or-later

View File

@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(argon C) project(argon C)
@@ -29,8 +33,19 @@ add_custom_command(
# Step 2: Custom target for lexer # Step 2: Custom target for lexer
add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H}) add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H})
set(SOURCES
external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c ${CFILES} ${LEXER_C}
)
if(NOT WIN32)
list(APPEND SOURCES external/linenoise/linenoise.c)
endif()
# Step 3: Add executable # Step 3: Add executable
add_executable(argon ${CFILES} ${LEXER_C}) add_executable(argon ${SOURCES})
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
target_include_directories(argon PRIVATE ${CMAKE_SOURCE_DIR}/external/cwalk/include)
target_include_directories(argon PRIVATE ${CMAKE_SOURCE_DIR}/external/libdye/include)
# Step 4: Build order # Step 4: Build order
add_dependencies(argon GenerateLexer) add_dependencies(argon GenerateLexer)
@@ -45,14 +60,16 @@ find_package(BDWgc REQUIRED)
find_package(gmp REQUIRED) find_package(gmp REQUIRED)
target_compile_options(argon PRIVATE -O3 -Wall -Wextra -Wno-unused-function -s) target_compile_options(argon PRIVATE -O3 -Wall -Wextra -Wno-unused-function -s)
target_link_options(argon PRIVATE -static)
target_link_libraries(argon PRIVATE target_link_libraries(argon PRIVATE
BDWgc::BDWgc BDWgc::BDWgc
gmp::gmp gmp::gmp
m m
$<$<PLATFORM_ID:Windows>:bcrypt>
) )
target_include_directories(argon PRIVATE target_include_directories(argon PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/lexer ${CMAKE_CURRENT_SOURCE_DIR}/src/lexer
) )
add_custom_command(TARGET argon POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:argon>)

View File

@@ -0,0 +1,3 @@
SPDX-FileCopyrightText: 2025 William Bell
SPDX-License-Identifier: GPL-3.0-or-later

67
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,67 @@
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
sh 'git submodule update --init --recursive'
}
}
stage('Setup Conan') {
steps {
sh '''
python3 -m venv /tmp/venv
. /tmp/venv/bin/activate
apt update
apt install -y cmake flex python3 python3-pip python3-venv
pip install --upgrade pip
pip install conan
'''
}
}
stage('Setup Conan Profile') {
steps {
sh '''
. /tmp/venv/bin/activate
if [ ! -f ~/.conan2/profiles/default ]; then
conan profile detect
fi
'''
}
}
stage('Install Dependencies') {
steps {
sh '''
. /tmp/venv/bin/activate
conan install . --build=missing
'''
}
}
stage('Build Project') {
steps {
sh '''
. /tmp/venv/bin/activate
conan build .
'''
}
}
stage('Archive Build Artifacts') {
steps {
sh '''
# Copy LICENSE.txt into build/bin
cp LICENSE.txt build/bin/
# Create tarball with the contents of build/bin at the root
tar -czf chloride.tar.gz -C build/bin .
'''
// Archive the tarball
archiveArtifacts artifacts: 'chloride.tar.gz', allowEmptyArchive: false
}
}
}
}

678
LICENSE
View File

@@ -1,678 +0,0 @@
This project is licensed under the GNU General Public License version 3 (GPLv3), except for
some files (e.g., in the `src/hash_data/siphash/` directory) which are licensed under CC0 1.0 Universal.
See the LICENSE-CC0 file in the respective directories for details.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

232
LICENSE.txt Normal file
View File

@@ -0,0 +1,232 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/philosophy/why-not-lgpl.html>.

121
LICENSES/CC0-1.0.txt Normal file
View File

@@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@@ -0,0 +1,232 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -1,33 +1,46 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
# Default FLEX tool
BINARY = bin/argon
FLEX_TOOL = flex
CFILES = external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c external/linenoise/linenoise.c $(shell find src -name '*.c')
LEXER_SRC = src/lexer/lex.l LEXER_SRC = src/lexer/lex.l
LEXER_C = src/lexer/lex.yy.c LEXER_C = src/lexer/lex.yy.c
LEXER_H = src/lexer/lex.yy.h LEXER_H = src/lexer/lex.yy.h
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function -Werror=unused-result -Iexternal/cwalk/include -Iexternal/libdye/include
CFILES = external/xxhash/xxhash.c $(shell find src -name '*.c') LDFLAGS = -lgc -lgmp -lm
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function
BINARY = bin/argon
all: $(BINARY) all: $(BINARY)
$(LEXER_C) $(LEXER_H): $(LEXER_SRC) $(LEXER_C) $(LEXER_H): $(LEXER_SRC)
flex --header-file=$(LEXER_H) -o $(LEXER_C) $(LEXER_SRC) $(FLEX_TOOL) --header-file=$(LEXER_H) -o $(LEXER_C) $(LEXER_SRC)
$(BINARY): $(CFILES) $(LEXER_C) $(LEXER_H) $(BINARY): $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -O3 -o $(BINARY) $(CFILES) $(CFLAGS) -s gcc -O3 -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS} -s
native: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin
gcc -O3 -march=native -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
debug: $(CFILES) $(LEXER_C) $(LEXER_H) debug: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -g -O0 -o $(BINARY) $(CFILES) $(CFLAGS) gcc -g -O3 -o $(BINARY) $(CFILES) $(CFLAGS)
full-debug: $(CFILES) $(LEXER_C) $(LEXER_H) full-debug: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -g -O0 -fsanitize=address -fno-omit-frame-pointer -o $(BINARY) $(CFILES) $(CFLAGS) gcc -g -O3 -fsanitize=address -fno-omit-frame-pointer -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
optimised: $(CFILES) $(LEXER_C) $(LEXER_H) optimised: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS) gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
${BINARY} rand_test.ar ${BINARY} rand_test.ar
gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS) gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
clean: clean:

View File

@@ -1,3 +1,82 @@
# Chloride <!--
SPDX-FileCopyrightText: 2025 William Bell
An Argon interpreter written in C SPDX-License-Identifier: GPL-3.0-or-later
-->
<div align="center">
<p>
<img width="150" src="logo/logo.png">
</p>
<h1>Chloride</h1>
</div>
Chloride is the new C-based interpreter for the Argon programming language.
It is designed as a drop-in replacement for the older Go implementation (argon-v3), while introducing a more efficient runtime and a cleaner, more consistent object model.
## Build
Currently, builds are only being made for linux x86_64 at [the projects Jenklins instance](https://jenkins.wbell.dev/job/chloride/).
If this does not satify your requirements, feel free to build for your platform. the dependancies are `conan`, `flex`, `cmake` and `gcc`.
install using conan.
```
conan install . --build=missing
```
and finally build using conan.
```
conan build .
```
the final build can be found in `build/bin`.
## Overview
Chloride aims to remain as interchangeable with argon-v3 as possible.
Most existing Argon code should run with minimal or no changes, and backwards compatibility is an ongoing priority.
Where behaviour differs, the goal is for those differences to be predictable and well-defined rather than accidental quirks.
This interpreter replaces argon-v3's AST-walking runtime with a proper bytecode compiler, caching system, and virtual machine.
The result is a more consistent execution model, lower memory usage, and improved overall performance, even though speed is not the sole focus of the project.
## Key Improvements Over argon-v3
- **Bytecode + VM architecture**
Chloride compiles source code into bytecode and executes it through a dedicated virtual machine.
The previous interpreter evaluated the AST directly at runtime, which limited performance and made optimisations difficult.
- **Reduced memory usage and CPU overhead**
Chloride is written in C with an emphasis on minimal allocations, predictable lifetimes, and efficient object handling.
- **Unified object model**
In contrast to argon-v3, where some values (such as numbers) were not objects, Chloride treats every value as a first-class object.
This simplifies the runtime and ensures a more consistent behaviour across all types.
- **Proper class and inheritance system**
Classes in Chloride are real objects, supporting inheritance and introspection in a clean, well-defined manner.
The old interpreter treated classes as a special-case construct, which restricted the language's expressiveness.
- **Backwards compatibility focus**
Chloride aims to match argon-v3s behaviour closely enough that most existing Argon programs run unchanged.
Compatibility fixes and behavioural parity are treated as long-term goals.
## Project Goals
- Maintain high compatibility with argon-v3.
- Minimise memory usage and improve runtime efficiency.
- Provide a stable, maintainable interpreter core.
- Keep the implementation straightforward so that future language features can be built cleanly on top of it.
- Serve as the reference interpreter for Argon going forward.
## Project Status
Chloride is still under active development.
The object model is largely complete, but several core language features are missing or experimental. Basic control flow constructs such as for loops are not implemented yet, partly because the older syntax was confusing and may be replaced with something clearer. While backwards compatibility is a goal, perfect compatibility is unlikely, especially where new syntax or improved semantics resolve long-standing issues in argon-v3.
The interpreter currently contains known performance issues and occasional segmentation faults, and part of the development process is identifying and removing these. The intention is to stabilise the runtime, finalise the syntax, and avoid any further major redesigns. The hope is that Chloride becomes both the long-term Argon interpreter and the last large rewrite the language needs.
# Licence
GNU General Public License v3.0

4
argon-package.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "carbon",
"version": "1.0.0"
}

View File

@@ -1,6 +1,11 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
from conan import ConanFile from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
from shutil import which from shutil import which
import os
class ArgonConan(ConanFile): class ArgonConan(ConanFile):
name = "argon" name = "argon"
@@ -11,12 +16,15 @@ class ArgonConan(ConanFile):
# Remove tool_requires, no flex from Conan # Remove tool_requires, no flex from Conan
requires = [ requires = [
"gmp/6.3.0", "gmp/6.3.0",
"bdwgc/8.2.8" "bdwgc/8.2.6"
] ]
default_options = { default_options = {
"gmp/*:shared": False, "gmp/*:shared": False,
"bdwgc/*:shared": False "bdwgc/*:shared": False,
"bdwgc/*:parallel_mark": False,
"bdwgc/*:threads": True,
"bdwgc/*:disable_debug": True,
} }
def layout(self): def layout(self):
@@ -25,20 +33,14 @@ class ArgonConan(ConanFile):
self.folders.generators = "build" self.folders.generators = "build"
def generate(self): def generate(self):
os.environ["CONAN_NON_INTERACTIVE"] = "1"
tc = CMakeToolchain(self) tc = CMakeToolchain(self)
# Try to find flex in system PATH first
flex_path = which("flex") flex_path = which("flex")
# If not found, fallback to flex from Conan build requirements
if not flex_path: if not flex_path:
flex_dep = self.dependencies.build.get("flex", None) raise Exception("Flex not found in system PATH. Please install flex on Linux/macOS.")
if not flex_dep:
raise Exception("Flex not found in system PATH and not declared as build requirement")
flex_path = join(flex_dep.package_folder, "bin", "flex")
tc.variables["FLEX_EXECUTABLE"] = flex_path
tc.variables["FLEX_EXECUTABLE"] = flex_path.replace("\\", "\\\\")
tc.generate() tc.generate()
def build(self): def build(self):

View File

@@ -1,126 +0,0 @@
import struct
from enum import Enum, EnumMeta, auto
class AutoEnumMeta(EnumMeta):
@classmethod
def __prepare__(metacls, clsname, bases, **kwargs):
d = super().__prepare__(clsname, bases, **kwargs)
d['_next_value'] = 254
return d
def _generate_next_value_(cls, name, start, count, last_values):
value = cls._next_value
cls._next_value += 1
return value
class OperationType(Enum, metaclass=AutoEnumMeta):
OP_LOAD_CONST = auto()
OP_DECLARE = auto()
OP_LOAD_NULL = auto()
OP_JUMP = auto()
class Types(Enum, metaclass=AutoEnumMeta):
TYPE_OP_STRING = auto()
TYPE_OP_NUMBER = auto()
def read_arbin(filename):
with open(filename, "rb") as f:
# Read and verify file identifier (4 bytes)
file_id = f.read(4)
if file_id != b"ARBI":
raise ValueError("Invalid file identifier")
# Read version number (uint64_t, little-endian)
version_number, = struct.unpack("<Q", f.read(8))
# Read regCount, constantsSize, bytecodeSize (all uint64_t, little-endian)
reg_count, = struct.unpack("<Q", f.read(8))
constants_size, = struct.unpack("<Q", f.read(8))
bytecode_size, = struct.unpack("<Q", f.read(8))
# Read constants buffer (raw bytes)
constants = f.read(constants_size)
# Read bytecode array (uint64_t, little-endian)
bytecode = []
for _ in range(bytecode_size):
instr, = struct.unpack("<Q", f.read(8))
bytecode.append(instr)
return {
"version": version_number,
"register_count": reg_count,
"constants_size": constants_size,
"bytecode_size": bytecode_size,
"constants": constants,
"bytecode": bytecode,
}
class print_opcode:
def start(registers,data, i):
print()
match data['bytecode'][i]:
case OperationType.OP_LOAD_CONST.value:
return print_opcode.OP_LOAD_CONST(registers,data, i)
case OperationType.OP_DECLARE.value:
return print_opcode.OP_DECLARE(registers,data, i)
case OperationType.OP_LOAD_NULL.value:
return print_opcode.OP_LOAD_NULL(registers,data, i)
def OP_LOAD_CONST(registers,data, i) -> int:
print("OP_LOAD_CONST ", end="")
i+=1
register = data["bytecode"][i]
print("To Register",register,"", end="")
i+=1
match data["bytecode"][i]:
case Types.TYPE_OP_STRING.value:
print("TYPE_OP_STRING ", end="")
case Types.TYPE_OP_NUMBER.value:
print("TYPE_OP_NUMBER ", end="")
i+=1
length = data["bytecode"][i]
i+=1
offset = data["bytecode"][i]
i+=1
print("Length",length,"", end="")
print("Offset",offset,"")
registers[register] = data["constants"][offset:offset+length].decode()
print("const value:", registers[register])
return i
def OP_DECLARE(registers,data, i) -> int:
print("OP_DECLARE ", end="")
i+=1
length = data["bytecode"][i]
i+=1
offset = data["bytecode"][i]
i+=1
from_register = data["bytecode"][i]
i+=1
print("Name Length",length,"", end="")
print("Name Offset",offset,"", end="")
print("From Register",from_register,"")
print("output: let", data['constants'][offset:offset+length].decode(),'=',registers[from_register])
return i
def OP_LOAD_NULL(registers,data, i) -> int:
print("OP_LOAD_NULL ", end="")
i+=1
to_register = data["bytecode"][i]
i+=1
print("To Register",to_register,"")
registers[to_register] = "null"
return i
if __name__ == "__main__":
filename = "out.arbin"
data = read_arbin(filename)
print(f"Version: {data['version']}")
print(f"Register Count: {data['register_count']}")
print(f"Constants Size: {data['constants_size']} bytes")
print(f"Bytecode Length: {data['bytecode_size']} elements")
registers = ["null"]*data['register_count']
i=0
while i<len(data["bytecode"]):
i=print_opcode.start(registers,data,i)

1
external/cwalk vendored Submodule

Submodule external/cwalk added at e98d23f688

1
external/libdye vendored Submodule

Submodule external/libdye added at 942c4dd39b

1
external/linenoise vendored Submodule

Submodule external/linenoise added at d895173d67

View File

@@ -1,54 +0,0 @@
let __makeFile(name, type, data) = do
let File = {name: name, type: type, data: data}
let save(path) = do
let file = file.write(path)
file.buffer(data)
file.close()
File.save = save
return File
let __multipart(req, res) = do
let boundary = buffer().from(req.headers["content-type"].splitN("boundary=", 2)[1])
let newLineSplit = buffer().from("\r\n\r\n")
let parts = req.buffer.body.split(boundary)
for (i from 0 to parts.length) do
let str = parts[i].to("string")
if (str == "" || str=="--" || str=="--\r\n") continue
str = null
let headers = {}
let lines = parts[i].splitN(newLineSplit, 2)
let headerLines = lines[0].to("string").split("\r\n")
for (j from 0 to headerLines.length) do
let header = headerLines[j].splitN(": ", 2)
if (header.length != 2) continue
headers[header[0].lower()] = header[1]
if (lines.length != 2) continue
let body = lines[1]
if (i != parts.length-1) do
body = body.slice(0, body.length-4)
if ("content-disposition" in headers) do
let disposition = headers["content-disposition"].split("; ")
if (disposition[0] == "form-data") do
let name = json.parse(disposition[1].splitN("=", 2)[1])
if (disposition.length >= 3) do
let filename = json.parse(disposition[2].splitN("=", 2)[1])
req.files[name] = __makeFile(filename, headers["content-type"], body)
else do
req.formdata[name] = body.to("string")
res.next()
let formdata(req, res) = do
req.formdata = {}
req.files = {}
if (req.method != "POST") return res.next()
if ("content-type" not in req.headers) return res.next()
let loweredContentType = req.headers["content-type"].lower()
if (loweredContentType.startswith("multipart/form-data")) return __multipart(req, res)
else if (loweredContentType.startswith("application/x-www-form-urlencoded")) req.formdata = url.decodeURLQuery(req.buffer.body.to("string"))
else if (loweredContentType.startswith("application/json")) req.formdata = json.parse(req.buffer.body.to("string"))
else req.files.file = __makeFile("file", req.headers["content-type"], req.buffer.body)
res.next()

View File

@@ -1,7 +0,0 @@
import random
myfile = open("rand_test.ar","w")
for i in range(10000000):
myfile.write("\"")
myfile.write(str(random.random())[2::])
myfile.write("\"\n")

1
iso-lock.json Normal file
View File

@@ -0,0 +1 @@
[{"Name":"http.ar","Version":"1.1.7","URL":"https://isotope.wbell.dev/isotope-download?name=http.ar\u0026version=1.1.7","Remote":"isotope.wbell.dev"}]

BIN
logo/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

84
logo/logo.svg Normal file
View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="logo.svg"
inkscape:export-filename="logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="1.6199927"
inkscape:cx="166.66742"
inkscape:cy="208.33427"
inkscape:window-width="2560"
inkscape:window-height="1414"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<rect
x="96.463768"
y="150.58824"
width="287.20887"
height="242.68713"
id="rect1" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="fill:#555555;fill-opacity:1"
id="path7"
inkscape:flatsided="false"
sodipodi:sides="17"
sodipodi:cx="150.15175"
sodipodi:cy="58.052856"
sodipodi:r1="46.661324"
sodipodi:r2="37.32906"
sodipodi:arg1="0.30400094"
sodipodi:arg2="0.48880051"
inkscape:rounded="0.4"
inkscape:randomized="2.7755576e-17"
d="m 194.67349,72.020461 c -1.44879,4.618019 -9.29136,-0.712277 -11.56404,3.560897 -2.27268,4.273175 6.53108,7.796197 3.5119,11.579008 -3.01918,3.782812 -8.40662,-4.020601 -12.06948,-0.856972 -3.66286,3.163629 3.27373,9.629034 -0.90807,12.065747 -4.18181,2.436719 -6.38654,-6.785922 -10.94489,-5.159103 -4.55835,1.626819 -0.42574,10.161412 -5.2054,10.922942 -4.77966,0.76152 -3.50391,-8.634768 -8.34212,-8.76447 -4.83821,-0.129703 -4.06772,9.32144 -8.79971,8.30493 -4.732,-1.01651 -0.14806,-9.317437 -4.61271,-11.186144 -4.46464,-1.868708 -7.16032,7.222558 -11.20557,4.565293 -4.04525,-2.657264 3.22778,-8.741737 -0.26032,-12.097069 -3.4881,-3.355333 -9.28589,4.148226 -12.09806,0.209088 -2.81217,-3.939138 6.1677,-6.985416 4.12723,-11.374218 -2.04047,-4.388801 -10.15735,0.513654 -11.35664,-4.175355 -1.19929,-4.689009 8.27463,-4.285677 7.95737,-9.115215 -0.31727,-4.829539 -9.65701,-3.190291 -9.08144,-7.995895 0.57556,-4.805603 9.26403,-1.007133 10.71282,-5.625152 1.44879,-4.61802 -7.85242,-6.463369 -5.57974,-10.736544 2.27268,-4.273174 9.00227,2.407431 12.02145,-1.375381 3.01917,-3.782811 -4.98733,-8.863533 -1.32447,-12.027163 3.66286,-3.163629 7.5247,5.496857 11.70651,3.060143 4.18181,-2.436714 -1.44866,-10.066629 3.10969,-11.693447 4.55835,-1.626819 5.03088,7.843901 9.81054,7.082377 4.77966,-0.761525 2.28565,-9.91017 7.12386,-9.780467 4.83821,0.129703 1.85761,9.131584 6.58961,10.148098 4.73199,1.016513 5.71126,-8.415288 10.17591,-6.546581 4.46464,1.868707 -1.56654,9.185997 2.47871,11.843261 4.04525,2.657265 8.36555,-5.783874 11.85365,-2.428541 3.4881,3.355332 -4.77911,7.999788 -1.96695,11.938927 2.81217,3.939138 9.89002,-2.371317 11.93049,2.017485 2.04047,4.388801 -7.34625,5.733164 -6.14696,10.422174 1.19929,4.689009 10.07879,1.3615 10.39605,6.191039 0.31727,4.829538 -8.92123,2.692245 -9.49679,7.497849 -0.57556,4.805603 8.90636,4.910439 7.45757,9.528459 z"
inkscape:transform-center-x="1.5847721"
inkscape:transform-center-y="-0.51694771"
transform="matrix(5.4829104,-0.55336355,0.55336355,5.4829104,-597.77534,21.197933)" />
<path
style="font-weight:bold;font-size:96px;font-family:'TeX Gyre Heros';-inkscape-font-specification:'TeX Gyre Heros, Bold';white-space:pre;inline-size:117.996;fill:#a9bacd"
d="m 231.18969,194.33982 h -14.016 c -0.864,8.928 -6.528,12.96 -15.456,12.96 -11.136,0 -17.664,-8.544 -17.664,-23.808 0,-15.456 6.816,-24.096 18.144,-24.096 7.776,0 12.864,3.552 14.976,12.576 h 13.728 c -1.248,-16.128 -13.44,-24.864 -29.184,-24.864 -19.776,0 -32.064,13.536 -32.064,36.192 0,22.464 12.192,36.096 31.68,36.096 17.376,0 28.992,-9.024 29.856,-25.056 z m 23.42401,23.904 v -69.984 h -13.44 v 69.984 z"
id="text2"
transform="matrix(4.4012947,0,0,3.7064713,-720.43857,-423.2176)"
aria-label="Cl" />
<rect
style="fill:#a9bacd;fill-opacity:1;stroke-width:0.783784"
id="rect4"
width="43.448219"
height="12.658142"
x="421.52911"
y="134.00171"
sodipodi:insensitive="true" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

2893
src/LICENSE_c.h Normal file

File diff suppressed because it is too large Load Diff

137
src/arobject.h Normal file
View File

@@ -0,0 +1,137 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef AROBJECT_H
#define AROBJECT_H
#include "dynamic_array/darray.h"
#include "runtime/internals/dynamic_array_armem/darray_armem.h"
#include "runtime/internals/hashmap/hashmap.h"
#include <gmp.h>
typedef enum {
__base__,
__class__,
__name__,
BUILT_IN_ARRAY_COUNT,
__binding__,
__function__,
__add__,
__string__,
__subtract__,
__multiply__,
__divide__,
__new__,
__init__,
__boolean__,
__getattr__,
field__address,
__call__,
__number__,
field_length,
__getattribute__,
__setattr__,
__getitem__,
__setitem__,
__hash__,
__repr__,
BUILT_IN_FIELDS_COUNT,
} built_in_fields;
typedef struct ArErr ArErr;
typedef struct RuntimeState RuntimeState;
typedef struct ArgonObject ArgonObject; // forward declaration
typedef ArgonObject *(*native_fn)(size_t argc, ArgonObject **argv, ArErr *err,
RuntimeState *state);
typedef enum ArgonType {
TYPE_NULL,
TYPE_BOOL,
TYPE_NUMBER,
TYPE_STRING,
TYPE_FUNCTION,
TYPE_NATIVE_FUNCTION,
TYPE_METHOD,
TYPE_DICTIONARY,
TYPE_OBJECT,
} ArgonType;
typedef struct {
void *data;
size_t capacity;
size_t size;
struct hashmap *hashmap;
} ConstantArena;
typedef struct {
uint8_t registerCount;
uint8_t registerAssignment;
DArray *return_jumps;
DArray bytecode;
ConstantArena constants;
char *path;
} Translated;
struct string_struct {
uint64_t prehash;
uint64_t hash;
char *data;
size_t length;
bool hash_computed;
};
typedef struct Stack {
uint64_t fake_new_scopes;
struct hashmap_GC *scope;
struct Stack *prev;
} Stack;
struct argon_function_struct {
Translated translated;
uint8_t *bytecode;
size_t bytecode_length;
Stack *stack;
size_t number_of_parameters;
struct string_struct *parameters;
uint64_t line;
uint64_t column;
};
struct built_in_slot {
built_in_fields field;
ArgonObject *value;
};
struct as_number {
union {
mpq_t *mpq;
int64_t i64;
} n;
bool is_int64;
};
// full definition of ArgonObject (no typedef again!)
struct ArgonObject {
struct hashmap_GC *dict;
size_t built_in_slot_length;
struct built_in_slot built_in_slot[BUILT_IN_ARRAY_COUNT];
union {
struct as_number *as_number;
struct hashmap_GC *as_hashmap;
struct string_struct *as_str;
native_fn native_fn;
struct argon_function_struct *argon_fn;
} value;
ArgonType type;
bool as_bool;
};
#endif // AROBJECT_H

View File

@@ -1,18 +1,21 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "darray.h" #include "darray.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "../memory.h"
void darray_init(DArray *arr, size_t element_size) { void darray_init(DArray *arr, size_t element_size) {
arr->element_size = element_size; arr->element_size = element_size;
arr->size = 0; arr->size = 0;
arr->capacity = CHUNK_SIZE; arr->capacity = CHUNK_SIZE / element_size;
arr->data = malloc(CHUNK_SIZE * element_size); arr->data = checked_malloc(CHUNK_SIZE); // fixed byte allocation
arr->resizable = true; arr->resizable = true;
if (!arr->data) {
fprintf(stderr, "darray_init: allocation failed\n");
exit(EXIT_FAILURE);
}
} }
void darray_resize(DArray *arr, size_t new_size) { void darray_resize(DArray *arr, size_t new_size) {
@@ -20,9 +23,17 @@ void darray_resize(DArray *arr, size_t new_size) {
fprintf(stderr, "darray_resize: unresizable darray\n"); fprintf(stderr, "darray_resize: unresizable darray\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
size_t new_capacity = ((new_size + CHUNK_SIZE) / CHUNK_SIZE) * CHUNK_SIZE;
// Determine number of full chunks needed to store new_size elements
size_t required_bytes = new_size * arr->element_size;
size_t new_capacity_bytes = required_bytes*2;
size_t new_capacity = new_capacity_bytes / arr->element_size;
if (!new_capacity) {
return;
}
if (new_capacity != arr->capacity) { if (new_capacity != arr->capacity) {
void *new_data = realloc(arr->data, new_capacity * arr->element_size); void *new_data = realloc(arr->data, new_capacity_bytes);
if (!new_data) { if (!new_data) {
fprintf(stderr, "darray_resize: reallocation failed\n"); fprintf(stderr, "darray_resize: reallocation failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@@ -1,10 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef DARRAY_H #ifndef DARRAY_H
#define DARRAY_H #define DARRAY_H
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#define CHUNK_SIZE 1048576 #define CHUNK_SIZE 4096
typedef struct { typedef struct {
void *data; void *data;

199
src/err.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "err.h"
#include "../external/libdye/include/dye.h"
#include <ctype.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
if (lineptr == NULL || n == NULL || stream == NULL) {
return -1;
}
size_t pos = 0;
int c;
if (*lineptr == NULL || *n == 0) {
*n = 128; // initial buffer size
*lineptr = malloc(*n);
if (*lineptr == NULL) {
return -1;
}
}
while ((c = fgetc(stream)) != EOF) {
// Resize buffer if needed
if (pos + 1 >= *n) {
size_t new_size = *n * 2;
char *new_ptr = realloc(*lineptr, new_size);
if (new_ptr == NULL) {
return -1;
}
*lineptr = new_ptr;
*n = new_size;
}
(*lineptr)[pos++] = (char)c;
if (c == '\n') {
break;
}
}
if (pos == 0 && c == EOF) {
return -1; // EOF and no data read
}
(*lineptr)[pos] = '\0';
return (ssize_t)pos;
}
#endif
const ArErr no_err = (ArErr){"", "", "", 0, 0, 0, false};
ArErr create_err(int64_t line, int64_t column, int length, char *path,
const char *type, const char *fmt, ...) {
ArErr err;
err.exists = true;
if (path)
strcpy(err.path, path);
else {
err.path[0] = '\0';
}
err.line = line;
err.column = column;
err.length = length;
// Copy error type safely
snprintf(err.type, sizeof(err.type), "%s", (char *)type);
// Format error message
va_list args;
va_start(args, fmt);
vsnprintf(err.message, sizeof(err.message), fmt, args);
va_end(args);
return err;
}
void output_err(ArErr err) {
if (!err.exists)
return;
dye(stderr, DYE_WHITE, DYE_RED);
fprintf(stderr, "ERROR!");
dye(stderr, DYE_RESET, DYE_RESET);
fprintf(stderr, " ");
dyefg(stderr, DYE_RED);
dye_style(stderr, DYE_STYLE_BOLD);
fprintf(stderr, "%s", err.type);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, ": ");
dyefg(stderr, DYE_RED);
fprintf(stderr, "%s", err.message);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "\n");
if (strlen(err.path) && err.line) {
dyefg(stderr, DYE_GRAY);
fprintf(stderr, " --> ");
dyefg(stderr, DYE_CYAN);
fprintf(stderr, "%s", err.path);
dyefg(stderr, DYE_GRAY);
fprintf(stderr, ":");
dyefg(stderr, DYE_YELLOW);
fprintf(stderr, "%" PRIu64, err.line);
dyefg(stderr, DYE_GRAY);
fprintf(stderr, ":");
dyefg(stderr, DYE_YELLOW);
fprintf(stderr, "%" PRIu64, err.column);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "\n");
FILE *file = fopen(err.path, "r");
if (file) {
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
int line_number_width = snprintf(NULL, 0, "%" PRIu64, err.line);
char *buffer = NULL;
size_t size = 0;
int current_line = 1;
ssize_t len;
while ((len = getline(&buffer, &size, file)) != -1) {
if (current_line == err.line) {
break;
}
current_line++;
}
fprintf(stderr, " ");
for (int i = 0; i < line_number_width; i++) {
fprintf(stderr, " ");
}
fprintf(stderr, "|\n");
for (ssize_t i = 0; i < len; i++) {
if (buffer[i] == '\n') {
buffer[i] = '\0';
break;
}
}
char *line_starts = buffer;
size_t skipped_chars = 0;
while (*line_starts && isspace((unsigned char)*line_starts) &&
line_starts - buffer < err.column - 1) {
line_starts++;
err.column--;
skipped_chars++;
}
fprintf(stderr, " %" PRIu64 " | ", err.line);
if (err.length) {
fprintf(stderr, "%.*s", (int)err.column - 1, line_starts);
dyefg(stderr, DYE_RED);
dye_style(stderr, DYE_STYLE_BOLD);
fprintf(stderr, "%.*s", err.length, line_starts + err.column - 1);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "%.*s",
(int)len - (int)skipped_chars - (int)err.column -
(int)err.length + 1,
line_starts + (int)err.column + err.length - 1);
for (int64_t i = 0; i < err.column - 1; i++) {
fprintf(stderr, " ");
}
} else {
fprintf(stderr, "%s", line_starts);
}
free(buffer);
fprintf(stderr, "\n ");
for (int i = 0; i < line_number_width; i++) {
fprintf(stderr, " ");
}
fprintf(stderr, "| ");
for (int i = 1; i < err.column; i++) {
fprintf(stderr, " ");
}
dyefg(stderr, DYE_RED);
dye_style(stderr, DYE_STYLE_BOLD);
for (int i = 0; i < err.length; i++) {
fprintf(stderr, "^");
}
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "\n");
}
}
}

16
src/err.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef RETURN_TYPE_H
#define RETURN_TYPE_H
#include "returnTypes.h"
extern const ArErr no_err;
ArErr create_err(int64_t line, int64_t column, int length, char *path, const char *type,
const char *fmt, ...);
void output_err(ArErr err);
#endif // RETURN_TYPE_H

View File

@@ -1,28 +1,44 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifdef _WIN32
#include <windows.h>
#include <bcrypt.h>
#else
#include <fcntl.h> #include <fcntl.h>
#include <stdint.h>
#include <unistd.h> #include <unistd.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include "siphash/siphash.h" #include "siphash/siphash.h"
#include "hash_data.h" #include "hash_data.h"
uint8_t siphash_key[16]; uint8_t siphash_key[16];
const uint8_t siphash_key_fixed_for_translator[16] = {218, 19, 245, 136, 128, 160, 122, 81, 249, 147, 111, 230, 174, 145, 125 ,218};
uint8_t empty_siphash_key[16]; uint8_t empty_siphash_key[16];
void generate_siphash_key(uint8_t hash_key[16]) { void generate_siphash_key(uint8_t hash_key[16]) {
#ifdef _WIN32
if (BCryptGenRandom(NULL, hash_key, 16, BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) {
// Fallback or abort
}
#else
int fd = open("/dev/urandom", O_RDONLY); int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0 || read(fd, hash_key, 16) != 16) { if (fd < 0 || read(fd, hash_key, 16) != 16) {
// Fallback or abort // Fallback or abort
} }
close(fd); close(fd);
#endif
} }
uint64_t siphash64_bytes(const void *data, size_t len,uint8_t hash_key[16]) { uint64_t siphash64_bytes(const void *data, size_t len,const uint8_t hash_key[16]) {
uint8_t out[8]; uint8_t out[8];
if (siphash(data, len, hash_key, out, sizeof(out)) != 0) if (siphash(data, len, hash_key, out, sizeof(out)) != 0)
return 0; return 0;
uint64_t hash = 0; return *(uint64_t *)out;
for (int i = 0; i < 8; ++i)
hash |= ((uint64_t)out[i]) << (8 * i);
return hash;
} }

View File

@@ -1,11 +1,18 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef HASH_DATA_H #ifndef HASH_DATA_H
#define HASH_DATA_H #define HASH_DATA_H
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
extern uint8_t siphash_key[16]; extern uint8_t siphash_key[16];
extern const uint8_t siphash_key_fixed_for_translator[16];
extern uint8_t empty_siphash_key[16]; extern uint8_t empty_siphash_key[16];
void generate_siphash_key(uint8_t siphash_key[16]); void generate_siphash_key(uint8_t siphash_key[16]);
uint64_t siphash64_bytes(const void *data, size_t len,uint8_t siphash_key[16]); uint64_t siphash64_bytes(const void *data, size_t len,const uint8_t hash_key[16]);
#endif //HASH_DATA_H #endif //HASH_DATA_H

View File

@@ -1,122 +0,0 @@
This license applies **only** to the files that explicitly state at the top of the file that they are under CC0 1.0 Universal.
All other files in this project are licensed under the GNU General Public License version 3 (GPLv3) unless otherwise stated.
Please refer to the LICENSE file in the root directory for the main project license.
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@@ -1,20 +1,6 @@
/* /*
* This file is dedicated to the public domain under CC0 1.0 Universal.
* See the LICENSE-CC0 file in this directory for details.
*
* SipHash reference C implementation
*
* Copyright (c) 2012-2022 Jean-Philippe Aumasson
* <jeanphilippe.aumasson@gmail.com>
* Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to> * Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
* * Copyright (c) 2012-2022 Jean-Philippe Aumasson
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
*/ */

View File

@@ -1,20 +1,6 @@
/* /*
* This file is dedicated to the public domain under CC0 1.0 Universal.
* See the LICENSE-CC0 file in this directory for details.
*
* SipHash reference C implementation
*
* Copyright (c) 2012-2022 Jean-Philippe Aumasson
* <jeanphilippe.aumasson@gmail.com>
* Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to> * Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
* * Copyright (c) 2012-2022 Jean-Philippe Aumasson
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
*/ */

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "hashmap.h" #include "hashmap.h"
#include "../memory.h" #include "../memory.h"
@@ -6,8 +12,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
struct hashmap *createHashmap() { struct hashmap *createHashmap() {
size_t size = 8; size_t size = 8;
@@ -20,21 +24,22 @@ struct hashmap *createHashmap() {
} }
void hashmap_free(struct hashmap *t, free_val_func free_val) { void hashmap_free(struct hashmap *t, free_val_func free_val) {
if (!t) return; if (!t)
return;
for (size_t i = 0; i < t->size; i++) { for (size_t i = 0; i < t->size; i++) {
struct node *current = t->list[i]; struct node *current = t->list[i];
while (current) { while (current) {
struct node *next = current->next; struct node *next = current->next;
if (free_val && current->val) { if (free_val && current->val) {
free_val(current->val); free_val(current->val);
} }
free(current); free(current);
current = next; current = next;
}
} }
free(t->list); }
free(t); free(t->list);
free(t);
} }
void resize_hashmap(struct hashmap *t) { void resize_hashmap(struct hashmap *t) {
@@ -56,13 +61,15 @@ void resize_hashmap(struct hashmap *t) {
while (temp) { while (temp) {
hashmap_insert(t, temp->hash, temp->key, temp->val, hashmap_insert(t, temp->hash, temp->key, temp->val,
temp->order); // Will increment count temp->order); // Will increment count
struct node *temp_temp = temp;
temp = temp->next; temp = temp->next;
free(temp_temp);
} }
} }
free(old_list); free(old_list);
} }
int hashCode(struct hashmap *t, uint64_t hash) { return hash % t->size; } int hashCode(struct hashmap *t, uint64_t hash) { return hash & (t->size - 1); }
int hashmap_remove(struct hashmap *t, uint64_t hash) { int hashmap_remove(struct hashmap *t, uint64_t hash) {
int pos = hashCode(t, hash); int pos = hashCode(t, hash);
@@ -86,8 +93,8 @@ int hashmap_remove(struct hashmap *t, uint64_t hash) {
return 0; return 0;
} }
void hashmap_insert(struct hashmap *t, uint64_t hash, void *key, void hashmap_insert(struct hashmap *t, uint64_t hash, void *key, void *val,
void *val, size_t order) { size_t order) {
if (!order) { if (!order) {
order = t->order++; order = t->order++;
} }

View File

@@ -1,10 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef HASHMAP_H #ifndef HASHMAP_H
#define HASHMAP_H #define HASHMAP_H
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
typedef struct ArgonObject ArgonObject;
typedef void (*free_val_func)(void *val); typedef void (*free_val_func)(void *val);
struct node { struct node {

482
src/import.c Normal file
View File

@@ -0,0 +1,482 @@
#include "../external/cwalk/include/cwalk.h"
#include "../external/xxhash/xxhash.h"
#include "arobject.h"
#include "err.h"
#include "hash_data/hash_data.h"
#include "hashmap/hashmap.h"
#include "lexer/lexer.h"
#include "lexer/token.h"
#include "runtime/internals/hashmap/hashmap.h"
#include "runtime/runtime.h"
#include "translator/translator.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <direct.h> // for _mkdir
#include <sys/stat.h> // for _stat
#include <windows.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#include <windows.h>
#else
#include <limits.h>
#include <unistd.h>
#endif
#include "err.h"
#include <pthread.h>
#if defined(_WIN32) || defined(_WIN64)
// Windows / MinGW usually uses little-endian, so these can be no-ops
// But define them explicitly to avoid implicit declaration warnings
static inline uint32_t le32toh(uint32_t x) { return x; }
static inline uint64_t le64toh(uint64_t x) { return x; }
static inline uint32_t htole32(uint32_t x) { return x; }
static inline uint64_t htole64(uint64_t x) { return x; }
#elif defined(__linux__)
#include <endian.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int is_regular_file(const char *path) {
struct stat path_stat;
stat(path, &path_stat);
return S_ISREG(path_stat.st_mode);
}
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define htole32(x) OSSwapHostToLittleInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
// Add others as needed
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <stdlib.h>
#include <sys/endian.h>
#endif
int ensure_dir_exists(const char *path) {
#ifdef _WIN32
struct _stat st;
if (_stat(path, &st) != 0) {
// Directory does not exist, create it
if (_mkdir(path) != 0) {
perror("_mkdir failed");
return -1;
}
} else if (!(st.st_mode & _S_IFDIR)) {
fprintf(stderr, "Path exists but is not a directory\n");
return -1;
}
#else
struct stat st;
if (stat(path, &st) != 0) {
// Directory does not exist, create it
if (mkdir(path, 0755) != 0) {
perror("mkdir failed");
return -1;
}
} else if (!S_ISDIR(st.st_mode)) {
fprintf(stderr, "Path exists but is not a directory\n");
return -1;
}
#endif
return 0;
}
char *CWD;
const char CACHE_FOLDER[] = "__arcache__";
const char FILE_IDENTIFIER[5] = "ARBI";
const char BYTECODE_EXTENTION[] = "arbin";
const uint32_t version_number = 0;
const char version_string[] = "4.0.0";
bool file_exists(const char *path) {
struct stat st;
if (stat(path, &st) == 0) {
return S_ISREG(st.st_mode); // true only if it's a regular file
}
return false; // doesn't exist, or stat failed
}
static inline void write_and_hash(FILE *file, XXH64_state_t *state,
const void *ptr, size_t size, size_t count) {
fwrite(ptr, size, count, file);
XXH64_update(state, ptr, size * count);
}
static inline void update_hash_from_file(FILE *file, XXH64_state_t *state,
size_t size) {
char buffer[4096];
size_t bytes_read;
size_t remaining = size;
while (remaining > 0 &&
(bytes_read =
fread(buffer, 1,
remaining > sizeof(buffer) ? sizeof(buffer) : remaining,
file)) > 0) {
XXH64_update(state, buffer, bytes_read);
remaining -= bytes_read;
}
}
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash,
char *source_path) {
FILE *bytecode_file = fopen(joined_paths, "rb");
if (!bytecode_file) {
fprintf(stderr, "cache doesnt exist... compiling from source.\n");
return 1;
}
// Find file size
fseek(bytecode_file, 0, SEEK_END);
long file_size = ftell(bytecode_file);
if (file_size < (long)sizeof(uint64_t)) {
goto FAILED;
}
fseek(bytecode_file, 0, SEEK_SET);
// Footer is the last 8 bytes
long data_size = file_size - sizeof(uint64_t);
// Set up hash state
XXH64_state_t *state = XXH64_createState();
XXH64_reset(state, 0);
// Hash everything except last 8 bytes
update_hash_from_file(bytecode_file, state, data_size);
// Read stored footer hash
uint64_t stored_hash_le;
if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) !=
sizeof(stored_hash_le)) {
XXH64_freeState(state);
goto FAILED;
}
uint64_t stored_hash = le64toh(stored_hash_le);
// Compare
uint64_t calc_hash = XXH64_digest(state);
XXH64_freeState(state);
if (calc_hash != stored_hash) {
fprintf(stderr, "cache hash mismatch (corrupted?)\n");
goto FAILED;
}
// Now actually parse the file contents
fseek(bytecode_file, 0, SEEK_SET); // rewind to start
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
if (fread(&file_identifier_from_cache, 1,
sizeof(file_identifier_from_cache) - 1,
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
sizeof(file_identifier_from_cache)) != 0) {
goto FAILED;
}
uint32_t read_version;
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
sizeof(read_version)) {
goto FAILED;
}
read_version = le32toh(read_version);
if (read_version != version_number) {
goto FAILED;
}
uint64_t read_hash;
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
sizeof(read_hash)) {
goto FAILED;
}
read_hash = le64toh(read_hash);
if (read_hash != hash) {
goto FAILED;
}
uint8_t register_count;
if (fread(&register_count, 1, sizeof(register_count), bytecode_file) !=
sizeof(register_count)) {
goto FAILED;
}
uint64_t constantsSize;
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
sizeof(constantsSize)) {
goto FAILED;
}
constantsSize = le64toh(constantsSize);
uint64_t bytecodeSize;
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
sizeof(bytecodeSize)) {
goto FAILED;
}
bytecodeSize = le64toh(bytecodeSize);
*translated_dest = init_translator(source_path);
translated_dest->registerCount = register_count;
arena_resize(&translated_dest->constants, constantsSize);
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
constantsSize) {
goto FAILED;
}
translated_dest->constants.size = constantsSize;
darray_resize(&translated_dest->bytecode, bytecodeSize);
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
bytecodeSize) {
goto FAILED;
}
translated_dest->bytecode.size = bytecodeSize;
fprintf(stderr, "cache exists and is valid, so will be used.\n");
fclose(bytecode_file);
return 0;
FAILED:
fprintf(stderr, "cache is invalid... compiling from source.\n");
fclose(bytecode_file);
return 1;
}
Translated load_argon_file(char *path, ArErr *err) {
clock_t start, end;
clock_t beginning = clock();
double time_spent, total_time_spent = 0;
const char *basename_ptr;
size_t basename_length;
cwk_path_get_basename(path, &basename_ptr, &basename_length);
if (!basename_ptr) {
*err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'",
path);
return (Translated){};
}
char basename[FILENAME_MAX];
memcpy(basename, basename_ptr, basename_length);
size_t parent_directory_length;
cwk_path_get_dirname(path, &parent_directory_length);
char parent_directory[FILENAME_MAX];
memcpy(parent_directory, path, parent_directory_length);
parent_directory[parent_directory_length] = '\0';
char cache_folder_path[FILENAME_MAX];
cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path,
sizeof(cache_folder_path));
char cache_file_path[FILENAME_MAX];
cwk_path_join(cache_folder_path, basename, cache_file_path,
sizeof(cache_file_path));
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION,
cache_file_path, sizeof(cache_file_path));
FILE *file = fopen(path, "r");
if (!file) {
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to open file '%s'",
path);
return (Translated){};
}
XXH3_state_t *hash_state = XXH3_createState();
XXH3_64bits_reset(hash_state);
char buffer[8192];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) {
XXH3_64bits_update(hash_state, buffer, bytes);
}
rewind(file);
uint64_t hash = XXH3_64bits_digest(hash_state);
XXH3_freeState(hash_state);
Translated translated;
if (load_cache(&translated, cache_file_path, hash, path) != 0) {
DArray tokens;
darray_init(&tokens, sizeof(Token));
LexerState state = {path, file, 0, 0, &tokens};
start = clock();
*err = lexer(state);
if (err->exists) {
darray_free(&tokens, free_token);
return (Translated){};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent);
fclose(state.file);
DArray ast;
darray_init(&ast, sizeof(ParsedValue));
start = clock();
*err = parser(path, &ast, &tokens, false);
darray_free(&tokens, free_token);
if (err->exists) {
darray_free(&ast, free_parsed);
return (Translated){};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Parser time taken: %f seconds\n", time_spent);
start = clock();
translated = init_translator(path);
*err = translate(&translated, &ast);
darray_free(&ast, free_parsed);
if (err->exists) {
darray_free(&translated.bytecode, NULL);
free(translated.constants.data);
hashmap_free(translated.constants.hashmap, NULL);
return (Translated){};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Translation time taken: %f seconds\n", time_spent);
#if defined(__linux__)
malloc_trim(0);
#endif
ensure_dir_exists(cache_folder_path);
file = fopen(cache_file_path, "wb");
uint64_t constantsSize = translated.constants.size;
uint64_t bytecodeSize = translated.bytecode.size;
uint32_t version_number_htole32ed = htole32(version_number);
uint64_t net_hash = htole64(hash);
constantsSize = htole64(constantsSize);
bytecodeSize = htole64(bytecodeSize);
XXH64_state_t *hash_state = XXH64_createState();
XXH64_reset(hash_state, 0);
write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char),
strlen(FILE_IDENTIFIER));
write_and_hash(file, hash_state, &version_number_htole32ed,
sizeof(uint32_t), 1);
write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1);
write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t),
1);
write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1);
write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1);
write_and_hash(file, hash_state, translated.constants.data, 1,
translated.constants.size);
write_and_hash(file, hash_state, translated.bytecode.data,
translated.bytecode.element_size, translated.bytecode.size);
// Finalize the hash
uint64_t file_hash = XXH64_digest(hash_state);
XXH64_freeState(hash_state);
// Convert to little-endian before writing if needed
uint64_t file_hash_le = htole64(file_hash);
fwrite(&file_hash_le, sizeof(file_hash_le), 1, file);
fclose(file);
}
hashmap_free(translated.constants.hashmap, NULL);
Translated gc_translated = {
translated.registerCount, translated.registerAssignment, NULL, {}, {},
translated.path};
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity +
translated.constants.capacity);
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
translated.bytecode.capacity);
gc_translated.bytecode.element_size = translated.bytecode.element_size;
gc_translated.bytecode.size = translated.bytecode.size;
gc_translated.bytecode.resizable = false;
gc_translated.bytecode.capacity =
translated.bytecode.size * translated.bytecode.element_size;
gc_translated.constants.data =
gc_translated.bytecode.data + translated.bytecode.capacity;
memcpy(gc_translated.constants.data, translated.constants.data,
translated.constants.capacity);
gc_translated.constants.size = translated.constants.size;
gc_translated.constants.capacity = translated.constants.capacity;
free(translated.bytecode.data);
free(translated.constants.data);
total_time_spent = (double)(clock() - beginning) / CLOCKS_PER_SEC;
fprintf(stderr, "total time taken loading file (%s): %f seconds\n", path,
total_time_spent);
return gc_translated;
}
const char *PRE_PATHS_TO_TEST[] = {"", "", "argon_modules", "argon_modules"};
const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST) / sizeof(char *)] = {
"", "init.ar", "", "init.ar"};
struct hashmap *importing_hash_table = NULL;
struct hashmap_GC *imported_hash_table = NULL;
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
char path[FILENAME_MAX];
bool found = false;
for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST) / sizeof(char *); i++) {
cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path,
sizeof(path));
cwk_path_get_absolute(path, path_relative, path, sizeof(path));
cwk_path_get_absolute(path, POST_PATHS_TO_TEST[i], path, sizeof(path));
if (file_exists(path)) {
found = true;
break;
}
}
if (!found) {
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to find file '%s'",
path_relative);
return NULL;
}
if (!importing_hash_table)
importing_hash_table = createHashmap();
uint64_t hash = siphash64_bytes(path, strlen(path), siphash_key);
hashmap_insert(importing_hash_table, hash, path, (void *)true, 0);
Translated translated = load_argon_file(path, err);
if (err->exists) {
return NULL;
}
clock_t start = clock(), end;
RuntimeState state = init_runtime_state(translated, path);
Stack *main_scope = create_scope(Global_Scope, true);
runtime(translated, state, main_scope, err);
if (err->exists) {
return NULL;
}
end = clock();
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Execution time taken: %f seconds\n", time_spent);
hashmap_insert(importing_hash_table, hash, path, (void *)false, 0);
if (!imported_hash_table)
imported_hash_table = createHashmap_GC();
hashmap_insert_GC(imported_hash_table, hash, path, main_scope, 0);
return main_scope;
}

17
src/import.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef IMPORT_H
#define IMPORT_H
#include "err.h"
extern char*CWD;
extern const char version_string[];
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err);
#endif // IMPORT_H

View File

@@ -1,3 +1,9 @@
/*
SPDX-FileCopyrightText: 2025 William Bell
SPDX-License-Identifier: GPL-3.0-or-later
*/
%option reentrant %option reentrant
%option yylineno %option yylineno
@@ -26,13 +32,6 @@ int yywrap(void * unused_param) {
":" { return TOKEN_COLON; } ":" { return TOKEN_COLON; }
"=" { return TOKEN_ASSIGN; } "=" { return TOKEN_ASSIGN; }
"+=" { return TOKEN_ASSIGN_PLUS; }
"-=" { return TOKEN_ASSIGN_MINUS; }
"//=" { return TOKEN_ASSIGN_FLOORDIV; }
"/=" { return TOKEN_ASSIGN_SLASH; }
"%=" { return TOKEN_ASSIGN_MODULO; }
"*=" { return TOKEN_ASSIGN_STAR; }
"^=" { return TOKEN_ASSIGN_CARET; }
"not"[ \t]+"in" { return TOKEN_NOT_IN; } "not"[ \t]+"in" { return TOKEN_NOT_IN; }
"in" { return TOKEN_IN; } "in" { return TOKEN_IN; }
@@ -91,7 +90,7 @@ int yywrap(void * unused_param) {
return TOKEN_STRING; return TOKEN_STRING;
} }
((([0-9]+(\.[0-9]+)?)|(\.[0-9]+))(e((\-|\+)?([0-9]+(\.[0-9]+)?)))?) { ((([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)((\-|\+)?([0-9]+)))?) {
return TOKEN_NUMBER; return TOKEN_NUMBER;
} }
@@ -107,9 +106,7 @@ int yywrap(void * unused_param) {
#[^\n]* { /* skip comment */ } #[^\n]* { /* skip comment */ }
. { .|((([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)((\-|\+)?([0-9]+(\.[0-9]+)?)))?) {
GET_STATE return TOKEN_INVALID;
fprintf(stderr, "%s:%zu:%zu error: unexpected character '%s'\n", state->path, state->current_line+1, COLUMN_NO+1, yytext);
exit(1);
} }
%% %%

View File

@@ -1,16 +1,20 @@
#include "lexer.h" /*
#include "lex.yy.h" * SPDX-FileCopyrightText: 2025 William Bell
#include "../string/string.h" *
* SPDX-License-Identifier: GPL-3.0-or-later
*/
void lexer(LexerState state) { #include "lexer.h"
#include "../string/string.h"
#include "lex.yy.h"
ArErr lexer(LexerState state) {
size_t line = 1; size_t line = 1;
size_t column = 1; size_t column = 1;
int ch; int ch;
while ((ch = fgetc(state.file)) != EOF) { while ((ch = fgetc(state.file)) != EOF) {
if (ch == 0 || (ch < 0x20 && ch != '\n' && ch != '\r' && ch != '\t')) { if (ch == 0 || (ch < 0x20 && ch != '\n' && ch != '\r' && ch != '\t')) {
fprintf(stderr, "%s:%zu:%zu error: disallowed character\n", state.path, return create_err(line, column, 1, state.path, "Syntax Error", "disallowed character");
line, column);
exit(1);
} }
if (ch == '\n') { if (ch == '\n') {
@@ -32,13 +36,16 @@ void lexer(LexerState state) {
int token; int token;
while ((token = yylex(scanner)) != 0) { while ((token = yylex(scanner)) != 0) {
Token token_struct = (Token){ if (token == TOKEN_INVALID) {
token, ArErr err = create_err(state.current_line + 1, state.current_column + 1,
state.current_line+1, yyget_leng(scanner), state.path, "Syntax Error",
state.current_column+1, "Invalid Token '%s'", yyget_text(scanner));
yyget_leng(scanner), yylex_destroy(scanner);
cloneString(yyget_text(scanner)) return err;
}; }
Token token_struct =
(Token){token, state.current_line + 1, state.current_column + 1,
yyget_leng(scanner), cloneString(yyget_text(scanner))};
darray_push(state.tokens, &token_struct); darray_push(state.tokens, &token_struct);
if (token == TOKEN_NEW_LINE) { if (token == TOKEN_NEW_LINE) {
state.current_line += 1; state.current_line += 1;
@@ -48,4 +55,5 @@ void lexer(LexerState state) {
} }
} }
yylex_destroy(scanner); yylex_destroy(scanner);
return no_err;
} }

View File

@@ -1,12 +1,19 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LEXER_H #ifndef LEXER_H
#define LEXER_H #define LEXER_H
#include "../dynamic_array/darray.h" #include "../dynamic_array/darray.h"
#include "token.h" #include "token.h"
#include <stdio.h> #include <stdio.h>
#include "../err.h"
typedef struct { typedef struct {
const char *path; char *path;
FILE *file; FILE *file;
size_t current_line; size_t current_line;
size_t current_column; size_t current_column;
@@ -14,6 +21,6 @@ typedef struct {
// add more fields as needed // add more fields as needed
} LexerState; } LexerState;
void lexer(LexerState state); ArErr lexer(LexerState state);
#endif // LEXER_H #endif // LEXER_H

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "token.h" #include "token.h"
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef TOKEN_H #ifndef TOKEN_H
#define TOKEN_H #define TOKEN_H
@@ -11,13 +17,6 @@ typedef enum {
TOKEN_INDENT, TOKEN_INDENT,
TOKEN_ASSIGN, TOKEN_ASSIGN,
TOKEN_ASSIGN_PLUS,
TOKEN_ASSIGN_MINUS,
TOKEN_ASSIGN_FLOORDIV,
TOKEN_ASSIGN_SLASH,
TOKEN_ASSIGN_MODULO,
TOKEN_ASSIGN_STAR,
TOKEN_ASSIGN_CARET,
// Operators // Operators
TOKEN_CARET, // ^ (Exponentiation) TOKEN_CARET, // ^ (Exponentiation)
@@ -25,8 +24,8 @@ typedef enum {
TOKEN_SLASH, // / (Division) TOKEN_SLASH, // / (Division)
TOKEN_FLOORDIV, // // (Floor Division) TOKEN_FLOORDIV, // // (Floor Division)
TOKEN_MODULO, // % (Modulo) TOKEN_MODULO, // % (Modulo)
TOKEN_PLUS, // + (Addition)
TOKEN_MINUS, // - (Subtraction) TOKEN_MINUS, // - (Subtraction)
TOKEN_PLUS, // + (Addition)
TOKEN_LT, // < TOKEN_LT, // <
TOKEN_GT, // > TOKEN_GT, // >
TOKEN_LE, // <= TOKEN_LE, // <=
@@ -72,10 +71,11 @@ typedef enum {
TOKEN_COMMA, TOKEN_COMMA,
TOKEN_COLON, TOKEN_COLON,
TOKEN_EXCLAMATION, TOKEN_EXCLAMATION,
} TokenType; TOKEN_INVALID,
} ArTokenType;
typedef struct { typedef struct {
TokenType type; ArTokenType type;
size_t line; size_t line;
size_t column; size_t column;
size_t length; size_t length;

View File

@@ -1,347 +1,81 @@
#include "dynamic_array/darray.h" /*
#include "lexer/lexer.h" * SPDX-FileCopyrightText: 2025 William Bell
#include "lexer/token.h" *
#include "memory.h" * SPDX-License-Identifier: GPL-3.0-or-later
#include "parser/parser.h" */
#include "runtime/runtime.h"
#include "translator/translator.h" #include "err.h"
#include "hashmap/hashmap.h"
#include "import.h"
#include "memory.h"
#include "runtime/objects/object.h"
#include "runtime/runtime.h"
#include "shell.h"
#include "../external/xxhash/xxhash.h"
#include "hash_data/hash_data.h" #include "hash_data/hash_data.h"
#include <arpa/inet.h>
#include <endian.h>
#include <locale.h> #include <locale.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#ifdef _WIN32 #ifdef _WIN32
#include <direct.h> #include <windows.h>
#define mkdir(path, mode) _mkdir(path) #endif
char *get_current_directory() {
char *buffer = NULL;
#ifdef _WIN32
DWORD size = GetCurrentDirectoryA(0, NULL);
buffer = malloc(size);
if (buffer == NULL)
return NULL;
if (GetCurrentDirectoryA(size, buffer) == 0) {
free(buffer);
return NULL;
}
#else #else
#include <sys/stat.h> long size = pathconf(".", _PC_PATH_MAX);
#include <sys/types.h> if (size == -1)
#endif size = 4096; // fallback
#include <string.h> buffer = malloc(size);
if (buffer == NULL)
int ensure_dir_exists(const char *path) { return NULL;
struct stat st = {0}; if (getcwd(buffer, size) == NULL) {
free(buffer);
if (stat(path, &st) == -1) { return NULL;
// Directory does not exist, create it
if (mkdir(path, 0755) != 0) {
perror("mkdir failed");
return -1;
}
}
return 0;
}
char *normalize_path(char *path) {
#ifdef _WIN32
for (char *p = path; *p; p++) {
if (*p == '/') {
*p = '\\';
}
}
#endif
return path;
}
// Join two paths using '/' as separator, no platform checks here.
int path_join(char *dest, size_t dest_size, const char *path1,
const char *path2) {
size_t len1 = strlen(path1);
size_t len2 = strlen(path2);
// Check if buffer is large enough (extra 2 for '/' and '\0')
if (len1 + len2 + 2 > dest_size)
return -1;
strcpy(dest, path1);
// Add '/' if needed
if (len1 > 0 && dest[len1 - 1] != '/') {
dest[len1] = '/';
dest[len1 + 1] = '\0';
len1++;
}
// Skip leading '/' in path2 to avoid double separator
if (len2 > 0 && path2[0] == '/') {
path2++;
len2--;
}
strcat(dest, path2);
return 0;
}
const char CACHE_FOLDER[] = "__arcache__";
const char FILE_IDENTIFIER[5] = "ARBI";
const char BYTECODE_EXTENTION[] = "arbin";
const uint32_t version_number = 0;
#ifdef _WIN32
#define PATH_SEP '\\'
#else
#define PATH_SEP '/'
#endif
char *replace_extension(const char *path, const char *new_ext) {
// Defensive: if new_ext doesn't start with '.', add it
int need_dot = (new_ext[0] != '.');
// Find last path separator to avoid changing dots in folder names
const char *last_sep = strrchr(path, PATH_SEP);
#ifdef _WIN32
// Windows can have '/' too as separator in practice, check it
const char *last_alt_sep = strrchr(path, '/');
if (last_alt_sep && (!last_sep || last_alt_sep > last_sep)) {
last_sep = last_alt_sep;
} }
#endif #endif
// Find last '.' after last_sep (if any) return buffer;
const char *last_dot = strrchr(path, '.');
if (last_dot && (!last_sep || last_dot > last_sep)) {
// Extension found: copy path up to last_dot, then append new_ext
size_t base_len = last_dot - path;
size_t ext_len = strlen(new_ext) + (need_dot ? 1 : 0);
size_t new_len = base_len + ext_len + 1;
char *result = malloc(new_len);
if (!result)
return NULL;
memcpy(result, path, base_len);
if (need_dot)
result[base_len] = '.';
strcpy(result + base_len + (need_dot ? 1 : 0), new_ext);
return result;
} else {
// No extension found: append '.' + new_ext (if needed)
size_t path_len = strlen(path);
size_t ext_len = strlen(new_ext) + (need_dot ? 1 : 0);
size_t new_len = path_len + ext_len + 1;
char *result = malloc(new_len);
if (!result)
return NULL;
strcpy(result, path);
if (need_dot)
strcat(result, ".");
strcat(result, new_ext);
return result;
}
}
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash) {
FILE *bytecode_file = fopen(joined_paths, "rb");
if (!bytecode_file)
return 1;
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)];
file_identifier_from_cache[strlen(FILE_IDENTIFIER)] = '\0';
if (fread(&file_identifier_from_cache, 1,
sizeof(file_identifier_from_cache) - 1,
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
sizeof(file_identifier_from_cache)) != 0) {
fclose(bytecode_file);
return 1;
}
uint32_t read_version;
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
sizeof(read_version)) {
goto FAILED;
}
read_version = le32toh(read_version);
if (read_version != version_number) {
goto FAILED;
}
uint64_t read_hash;
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
sizeof(read_hash)) {
goto FAILED;
}
read_hash = le64toh(read_hash);
if (read_hash != hash) {
goto FAILED;
}
uint8_t register_count;
if (fread(&register_count, 1, sizeof(register_count), bytecode_file) !=
sizeof(register_count)) {
goto FAILED;
}
uint64_t constantsSize;
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
sizeof(constantsSize)) {
goto FAILED;
}
constantsSize = le64toh(constantsSize);
uint64_t bytecodeSize;
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
sizeof(bytecodeSize)) {
goto FAILED;
}
bytecodeSize = le64toh(bytecodeSize);
arena_resize(&translated_dest->constants, constantsSize);
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
constantsSize) {
goto FAILED;
}
darray_resize(&translated_dest->bytecode, bytecodeSize);
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
bytecodeSize) {
goto FAILED;
}
translated_dest->registerCount = register_count;
fclose(bytecode_file);
return 0;
FAILED:
fclose(bytecode_file);
return 1;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
generate_siphash_key(siphash_key);
clock_t start, end;
double time_spent, total_time_spent = 0;
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
if (argc <= 1)
return -1;
ar_memory_init(); ar_memory_init();
char *path = argv[1]; generate_siphash_key(siphash_key);
init_built_in_field_hashes();
FILE *file = fopen(path, "r"); bootstrap_types();
if (!file) { bootstrap_globals();
return -1; if (argc <= 1)
return shell();
CWD = get_current_directory();
char *path_non_absolute = argv[1];
ArErr err = no_err;
ar_import(CWD, path_non_absolute, &err);
if (err.exists) {
output_err(err);
return 1;
} }
free(CWD);
XXH3_state_t *hash_state = XXH3_createState(); ar_memory_shutdown();
XXH3_64bits_reset(hash_state); if (runtime_hash_table)
hashmap_free(runtime_hash_table, NULL);
char buffer[8192]; if (err.exists) {
size_t bytes; output_err(err);
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) { return 1;
XXH3_64bits_update(hash_state, buffer, bytes);
} }
rewind(file); // Your main thread code
uint64_t hash = XXH3_64bits_digest(hash_state);
XXH3_freeState(hash_state);
char *filename_without_extention =
replace_extension(path, BYTECODE_EXTENTION);
size_t joined_paths_length =
strlen(CACHE_FOLDER) + strlen(filename_without_extention) + 2;
char *joined_paths = checked_malloc(joined_paths_length);
path_join(joined_paths, joined_paths_length, CACHE_FOLDER,
filename_without_extention);
free(filename_without_extention);
filename_without_extention = NULL;
Translated translated = init_translator();
if (load_cache(&translated, joined_paths, hash) != 0) {
free_translator(&translated);
translated = init_translator();
DArray tokens;
darray_init(&tokens, sizeof(Token));
LexerState state = {path, file, 0, 0, &tokens};
start = clock();
lexer(state);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Lexer time taken: %f seconds\n", time_spent);
fclose(state.file);
DArray ast;
darray_init(&ast, sizeof(ParsedValue));
start = clock();
parser(path, &ast, &tokens, false);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Parser time taken: %f seconds\n", time_spent);
darray_free(&tokens, free_token);
start = clock();
translate(&translated, &ast);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Translation time taken: %f seconds\n", time_spent);
darray_free(&ast, free_parsed);
ensure_dir_exists(CACHE_FOLDER);
file = fopen(joined_paths, "wb");
uint64_t constantsSize = (uint64_t)translated.constants.size;
uint64_t bytecodeSize = (uint64_t)translated.bytecode.size;
uint32_t version_number_htole32ed = htole32(version_number);
uint64_t net_hash = htole64(hash);
constantsSize = htole64(constantsSize);
bytecodeSize = htole64(bytecodeSize);
fwrite(&FILE_IDENTIFIER, sizeof(char), strlen(FILE_IDENTIFIER), file);
fwrite(&version_number_htole32ed, sizeof(uint32_t), 1, file);
fwrite(&net_hash, sizeof(net_hash), 1, file);
fwrite(&translated.registerCount, sizeof(uint8_t), 1, file);
fwrite(&constantsSize, sizeof(uint64_t), 1, file);
fwrite(&bytecodeSize, sizeof(uint64_t), 1, file);
fwrite(translated.constants.data, 1, translated.constants.size, file);
fwrite(translated.bytecode.data, translated.bytecode.element_size,
translated.bytecode.size, file);
fclose(file);
}
init_types();
start = clock();
runtime(translated);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Execution time taken: %f seconds\n", time_spent);
printf("total time taken: %f seconds\n", total_time_spent);
free_translator(&translated);
free(joined_paths);
return 0; return 0;
} }

View File

@@ -1,6 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "memory.h" #include "memory.h"
#include <gc/gc.h> #include <gc.h>
#include <gmp.h> #include <pthread.h>
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> // for malloc/free (temp arena fallback) #include <stdlib.h> // for malloc/free (temp arena fallback)
#include <string.h> #include <string.h>
@@ -14,27 +21,57 @@ void *checked_malloc(size_t size) {
return ptr; return ptr;
} }
void *gmp_gc_realloc(void *ptr, size_t old_size, size_t new_size) { void *checked_realloc(void *ptr, size_t size) {
(void)old_size; // Ignore old_size, Boehm doesn't need it void *new_ptr = realloc(ptr, size);
return GC_realloc(ptr, new_size); if (!new_ptr) {
fprintf(stderr, "fatal error: failed to allocate %zu bytes\n", size);
exit(EXIT_FAILURE);
}
return new_ptr;
} }
void gmp_gc_free(void *ptr, size_t size) { struct allocation *memory_allocations = NULL;
(void)size; // Boehm GC manages this itself size_t memory_allocations_size = 0;
// No-op — memory will be collected automatically pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
GC_FREE(ptr);
}
void ar_memory_init() { void ar_memory_init() {
GC_INIT(); GC_INIT();
mp_set_memory_functions(GC_malloc, gmp_gc_realloc, gmp_gc_free); // memory_allocations_size = 8;
// memory_allocations = malloc(memory_allocations_size*sizeof(struct
// allocation));
} }
void *ar_alloc(size_t size) { return GC_MALLOC(size); } void ar_memory_shutdown() {
// for (size_t i = 0; i<memory_allocations_size;i++) {
// if (memory_allocations[i].status != allocation_fully_freed) {
// free(memory_allocations[i].ptr);
// }
// }
// free(memory_allocations);
}
void *ar_alloc(size_t size) {
void *ptr = GC_MALLOC(size);
if (!ptr) {
fprintf(stderr, "panic: unable to allocate memory\n");
exit(EXIT_FAILURE);
}
return ptr;
}
void *ar_realloc(void *old, size_t size) {
void *ptr = GC_REALLOC(old, size);
if (!ptr) {
fprintf(stderr, "panic: unable to allocate memory\n");
exit(EXIT_FAILURE);
}
return ptr;
}
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data, void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
GC_finalization_proc *old_fn, void **old_client_data) { GC_finalization_proc *old_fn, void **old_client_data) {
return GC_register_finalizer_no_order(obj, fn, client_data, old_fn, old_client_data); return GC_register_finalizer_no_order(obj, fn, client_data, old_fn,
old_client_data);
} }
void *ar_alloc_atomic(size_t size) { return GC_MALLOC_ATOMIC(size); } void *ar_alloc_atomic(size_t size) { return GC_MALLOC_ATOMIC(size); }

View File

@@ -1,20 +1,42 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef ARGON_MEMORY_H #ifndef ARGON_MEMORY_H
#define ARGON_MEMORY_H #define ARGON_MEMORY_H
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <gc/gc.h> #include <stdbool.h>
#include <gc.h>
// GC-managed allocations // GC-managed allocations
typedef enum allocation_status {
allocation_used,
allocation_soft_free, // avaiable for use, since it hasnt been freed but isnt in use.
allocation_fully_freed,
} allocation_status;
struct allocation {
void*ptr;
size_t size;
allocation_status status;
};
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data, void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
GC_finalization_proc *old_fn, void **old_client_data); GC_finalization_proc *old_fn, void **old_client_data);
void *ar_alloc(size_t size); void *ar_alloc(size_t size);
void *ar_realloc(void * old,size_t size);
void *ar_alloc_atomic(size_t size); void *ar_alloc_atomic(size_t size);
char *ar_strdup(const char *str); char *ar_strdup(const char *str);
// Memory init/shutdown // Memory init/shutdown
void ar_memory_init(); void ar_memory_init();
void ar_memory_shutdown();
void *checked_malloc(size_t size); void *checked_malloc(size_t size);
void *checked_realloc(void *ptr, size_t size);
#endif // ARGON_MEMORY_H #endif // ARGON_MEMORY_H

View File

@@ -1,57 +1,64 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "access.h" #include "access.h"
#include "../../../lexer/token.h" #include "../../../lexer/token.h"
#include "../../../memory.h" #include "../../../memory.h"
#include "../../string/string.h"
#include "../../parser.h" #include "../../parser.h"
#include "../../string/string.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ParsedValue *parse_access(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
ParsedValue *to_access) { ParsedValue *to_access) {
Token *first_token = darray_get(tokens, *index);
(*index)++;
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
parsedAccess->to_access = *to_access; parsedAccess->to_access = to_access;
free(to_access); parsedAccess->access = NULL;
darray_init(&parsedAccess->access, sizeof(ParsedValue));
if (first_token->type == TOKEN_DOT) {
error_if_finished(file, tokens, index);
Token *token = darray_get(tokens, *index);
ParsedValue *parsedString = parse_string(token, false);
darray_push(&parsedAccess->access, parsedString);
free(parsedString);
} else {
while (true) {
skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index);
ParsedValue *parsedValue = parse_token(file, tokens, index, true);
darray_push(&parsedAccess->access, parsedValue);
free(parsedValue);
skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index);
Token *token = darray_get(tokens, *index);
if (token->type == TOKEN_RBRACKET) {
break;
} else if (token->type != TOKEN_COLON) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file,
token->line, token->column);
exit(EXIT_FAILURE);
}
(*index)++;
}
}
parsedValue->type = AST_ACCESS; parsedValue->type = AST_ACCESS;
parsedValue->data = parsedAccess; parsedValue->data = parsedAccess;
(*index)++; (*index)++;
return parsedValue; ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_IDENTIFIER) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected identifier after dot"),
NULL};
}
parsedAccess->line = token->line;
parsedAccess->column = token->column;
parsedAccess->length = token->length;
ParsedValueReturn parsedString = parse_string(token, false);
if (parsedString.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return parsedString;
}
parsedAccess->access = parsedString.value;
(*index)++;
return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_access(void *ptr) { void free_parse_access(void *ptr) {
ParsedValue *parsedValue = ptr; ParsedValue *parsedValue = ptr;
ParsedAccess *parsedAccess = parsedValue->data; ParsedAccess *parsedAccess = parsedValue->data;
free_parsed(&parsedAccess->to_access); free_parsed(parsedAccess->to_access);
darray_free(&parsedAccess->access, free_parsed); free(parsedAccess->to_access);
if (parsedAccess->access) {
free_parsed(parsedAccess->access);
free(parsedAccess->access);
}
free(parsedAccess); free(parsedAccess);
} }

View File

@@ -1,15 +1,25 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef ACCESS_H #ifndef ACCESS_H
#define ACCESS_H #define ACCESS_H
#include "../../parser.h" #include "../../parser.h"
#include "../../../lexer/token.h" // for Token #include "../../../lexer/token.h" // for Token
typedef struct { typedef struct {
ParsedValue to_access; ParsedValue *to_access;
DArray access; ParsedValue *access;
size_t line;
size_t column;
size_t length;
} ParsedAccess; } ParsedAccess;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_access(char*file,DArray *tokens, size_t * index, ParsedValue * to_access); ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
ParsedValue *to_access);
void free_parse_access(void *ptr); void free_parse_access(void *ptr);

View File

@@ -1,53 +1,127 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "assign.h" #include "assign.h"
#include "../../../lexer/token.h" #include "../../../lexer/token.h"
#include "../../../memory.h" #include "../../../memory.h"
#include "../../function/function.h"
#include "../../parser.h" #include "../../parser.h"
#include "../../string/string.h"
#include "../access/access.h"
#include "../call/call.h" #include "../call/call.h"
#include "../identifier/identifier.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
ParsedValue *parse_assign(char *file, DArray *tokens, ParsedValue *assign_to, ParsedValueReturn parse_assign(char *file, DArray *tokens,
size_t *index) { ParsedValue *assign_to, size_t *index) {
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
bool is_function = false;
char *function_name;
bool to_free_function_name = false;
DArray function_args;
ParsedValue *function_assign_to;
switch (assign_to->type) { switch (assign_to->type) {
case AST_IDENTIFIER: case AST_IDENTIFIER:
case AST_ACCESS: case AST_ACCESS:
break; break;
case AST_CALL:; case AST_CALL:;
ParsedCall *call = assign_to->data; ParsedCall *call = assign_to->data;
darray_init(&function_args, sizeof(char *));
for (size_t i = 0; i < call->args.size; i++) { for (size_t i = 0; i < call->args.size; i++) {
if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) { ParsedValue *arg = darray_get(&call->args, i);
fprintf(stderr, if (arg->type != AST_IDENTIFIER) {
"%s:%zu:%zu error: parameter names need to start with a letter " free_parsed(assign_to);
free(assign_to);
darray_free(&function_args, free_parameter);
return (ParsedValueReturn){
create_err(
token->line, token->column, token->length, file, "Syntax Error",
"parameter names need to start with a letter "
"or _, " "or _, "
"only use letters, digits, or _, and can't be keywords.\n", "only use letters, digits, or _, and can't be keywords."),
file, token->line, token->column); NULL};
exit(EXIT_FAILURE);
} }
char *param = strdup(((ParsedIdentifier *)arg->data)->name);
darray_push(&function_args, &param);
}
darray_free(&call->args, free_parsed);
is_function = true;
function_assign_to = call->to_call;
switch (function_assign_to->type) {
case AST_IDENTIFIER:
function_name = ((ParsedIdentifier *)function_assign_to->data)->name;
break;
case AST_ACCESS:
if (((ParsedAccess *)function_assign_to->data)->access->type ==
AST_STRING) {
ParsedString *name =
((ParsedAccess *)function_assign_to->data)->access->data;
function_name = checked_malloc(name->length + 1);
function_name[name->length] = 0;
memcpy(function_name, name->string, name->length);
to_free_function_name = true;
break;
}
// FALL THROUGH
default:
function_name = "anonymous";
break;
} }
break; break;
default: default:;
fprintf(stderr, "%s:%zu:%zu error: can't assign to %s\n", file, token->line, ArErr err = create_err(token->line, token->column, token->length, file,
token->column, ValueTypeNames[assign_to->type]); "Syntax Error", "can't assign to %s",
exit(EXIT_FAILURE); ValueTypeNames[assign_to->type]);
free_parsed(assign_to);
free(assign_to);
return (ParsedValueReturn){err, NULL};
}
(*index)++;
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(assign_to);
free(assign_to);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index);
ParsedValueReturn from = parse_token(file, tokens, index, true);
if (from.err.exists) {
free_parsed(assign_to);
free(assign_to);
return from;
}
if (!from.value) {
free_parsed(assign_to);
free(assign_to);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
}
if (is_function) {
from.value =
create_parsed_function(function_name, function_args, from.value);
if (to_free_function_name) free(function_name);
free(assign_to->data);
free(assign_to);
assign_to = function_assign_to;
} }
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign)); ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
assign->to = assign_to; assign->to = assign_to;
assign->type = token->type; assign->type = 0;
(*index)++; assign->from = NULL;
error_if_finished(file, tokens, index);
token = darray_get(tokens, *index);
assign->from = parse_token(file, tokens, index, true);
if (!assign->from) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line,
token->column);
exit(EXIT_FAILURE);
}
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_ASSIGN; parsedValue->type = AST_ASSIGN;
parsedValue->data = assign; parsedValue->data = assign;
return parsedValue; assign->from = from.value;
return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_assign(void *ptr) { void free_parse_assign(void *ptr) {
@@ -55,7 +129,9 @@ void free_parse_assign(void *ptr) {
ParsedAssign *parsedAssign = parsedValue->data; ParsedAssign *parsedAssign = parsedValue->data;
free_parsed(parsedAssign->to); free_parsed(parsedAssign->to);
free(parsedAssign->to); free(parsedAssign->to);
free_parsed(parsedAssign->from); if (parsedAssign->from) {
free(parsedAssign->from); free_parsed(parsedAssign->from);
free(parsedAssign->from);
}
free(parsedAssign); free(parsedAssign);
} }

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef ASSIGN_H #ifndef ASSIGN_H
#define ASSIGN_H #define ASSIGN_H
#include "../../parser.h" #include "../../parser.h"
@@ -5,12 +11,12 @@
typedef struct { typedef struct {
ParsedValue * to; ParsedValue * to;
TokenType type; ArTokenType type;
ParsedValue * from; ParsedValue * from;
} ParsedAssign; } ParsedAssign;
ParsedValue *parse_assign(char*file, DArray *tokens, ParsedValueReturn parse_assign(char *file, DArray *tokens, ParsedValue *assign_to,
ParsedValue *assign_to, size_t *index); size_t *index);
void free_parse_assign(void*ptr); void free_parse_assign(void*ptr);

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "call.h" #include "call.h"
#include "../../../lexer/token.h" #include "../../../lexer/token.h"
#include "../../../memory.h" #include "../../../memory.h"
@@ -6,41 +12,86 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ParsedValue *parse_call(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_call(char *file, DArray *tokens, size_t *index,
ParsedValue *to_call) { ParsedValue *to_call) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedCall *call = checked_malloc(sizeof(ParsedCall)); ParsedCall *call = checked_malloc(sizeof(ParsedCall));
Token *token = darray_get(tokens, *index);
call->line = token->line;
call->column = token->column;
call->to_call = to_call; call->to_call = to_call;
parsedValue->data = call; parsedValue->data = call;
parsedValue->type = AST_CALL; parsedValue->type = AST_CALL;
darray_init(&call->args, sizeof(ParsedValue)); darray_init(&call->args, sizeof(ParsedValue));
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
Token *token = darray_get(tokens, *index); if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index);
if (token->type != TOKEN_RPAREN) { if (token->type != TOKEN_RPAREN) {
while ((*index) < tokens->size) { while ((*index) < tokens->size) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
ParsedValue *parsedArg = parse_token(file, tokens, index, true); if (err.exists) {
darray_push(&call->args, parsedArg); free_parsed(parsedValue);
free(parsedArg); free(parsedValue);
error_if_finished(file, tokens, index); return (ParsedValueReturn){err, NULL};
}
ParsedValueReturn parsedArg = parse_token(file, tokens, index, true);
if (parsedArg.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return parsedArg;
} else if (!parsedArg.value) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected argument"),
NULL};
}
darray_push(&call->args, parsedArg.value);
free(parsedArg.value);
err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RPAREN) { if (token->type == TOKEN_RPAREN) {
break; break;
} else if (token->type != TOKEN_COMMA) { } else if (token->type != TOKEN_COMMA) {
fprintf(stderr, "%s:%zu:%zu error: expected comma\n", file, token->line, free_parsed(parsedValue);
token->column); free(parsedValue);
exit(EXIT_FAILURE);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected comma"),
NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
} }
} }
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_call(void *ptr) { void free_parse_call(void *ptr) {

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef CALL_H #ifndef CALL_H
#define CALL_H #define CALL_H
#include "../../parser.h" #include "../../parser.h"
@@ -6,10 +12,12 @@
typedef struct { typedef struct {
ParsedValue * to_call; ParsedValue * to_call;
DArray args; DArray args;
uint64_t line;
uint64_t column;
} ParsedCall; } ParsedCall;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_call(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_call(char *file, DArray *tokens, size_t *index,
ParsedValue *to_call); ParsedValue *to_call);
void free_parse_call(void *ptr); void free_parse_call(void *ptr);

View File

@@ -1,12 +1,31 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "identifier.h" #include "identifier.h"
#include "../../../lexer/token.h" #include "../../../lexer/token.h"
#include "../../parser.h" #include "../../parser.h"
#include <string.h> #include <string.h>
#include "../../../memory.h" #include "../../../memory.h"
ParsedValue *parse_identifier(Token *token) {
ParsedValueReturn parse_identifier(Token *token) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedIdentifier *parsedIdentifier = checked_malloc(sizeof(ParsedIdentifier));
parsedIdentifier->name = strcpy(checked_malloc(token->length + 1), token->value);
parsedIdentifier->line = token->line;
parsedIdentifier->column = token->column;
parsedValue->type = AST_IDENTIFIER; parsedValue->type = AST_IDENTIFIER;
parsedValue->data = strcpy(checked_malloc(strlen(token->value) + 1), token->value); parsedValue->data = parsedIdentifier;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
}
void free_identifier(void *ptr) {
ParsedValue *parsedValue = ptr;
ParsedIdentifier *parsed = parsedValue->data;
free(parsed->name);
free(parsed);
} }

View File

@@ -1,9 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef IDENTIFIER_H #ifndef IDENTIFIER_H
#define IDENTIFIER_H #define IDENTIFIER_H
#include "../../parser.h" #include "../../parser.h"
#include "../../../lexer/token.h" // for Token #include "../../../lexer/token.h" // for Token
typedef struct {
char * name;
size_t line;
size_t column;
} ParsedIdentifier;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue * parse_identifier(Token * token); ParsedValueReturn parse_identifier(Token *token);
void free_identifier(void *ptr);
#endif // IDENTIFIER_H #endif // IDENTIFIER_H

View File

@@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "item.h"
#include "../../../lexer/token.h"
#include "../../../memory.h"
#include "../../parser.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index,
ParsedValue *to_access) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedItemAccess *parsedItemAccess = checked_malloc(sizeof(ParsedItemAccess));
parsedItemAccess->to_access = to_access;
size_t capacity = 4;
parsedItemAccess->items = checked_malloc(capacity * sizeof(ParsedValue *));
parsedItemAccess->itemc = 0;
parsedValue->type = AST_ITEM_ACCESS;
parsedValue->data = parsedItemAccess;
Token *token = darray_get(tokens, *index);
parsedItemAccess->line = token->line;
parsedItemAccess->column = token->column;
parsedItemAccess->length = token->length;
(*index)++;
while (true) {
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
ParsedValueReturn parsedKey = parse_token(file, tokens, index, true);
if (parsedKey.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return parsedKey;
}
parsedItemAccess->items[parsedItemAccess->itemc++] = parsedKey.value;
if (parsedItemAccess->itemc > capacity) {
capacity *= 2;
parsedItemAccess->items = checked_realloc(
parsedItemAccess->items, capacity * sizeof(ParsedValue *));
}
Token *token = darray_get(tokens, *index);
(*index)++;
if (token->type == TOKEN_COMMA) {
continue;
} else if (token->type == TOKEN_RBRACKET) {
break;
} else {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error",
"expected either a comma or a closing bracket"),
NULL};
}
}
return (ParsedValueReturn){no_err, parsedValue};
}
void free_parse_item_access(void *ptr) {
ParsedValue *parsedValue = ptr;
ParsedItemAccess *parsedItemAccess = parsedValue->data;
free_parsed(parsedItemAccess->to_access);
free(parsedItemAccess->to_access);
for (size_t i = 0; i < parsedItemAccess->itemc; i++) {
free_parsed(parsedItemAccess->items[i]);
free(parsedItemAccess->items[i]);
}
free(parsedItemAccess->items);
free(parsedItemAccess);
}

View File

@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef ITEM_ACCESS_H
#define ITEM_ACCESS_H
#include "../../parser.h"
#include "../../../lexer/token.h" // for Token
typedef struct {
ParsedValue *to_access;
ParsedValue **items;
size_t itemc;
size_t line;
size_t column;
size_t length;
} ParsedItemAccess;
ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index,
ParsedValue *to_access);
void free_parse_item_access(void *ptr);
#endif // ACCESS_H

View File

@@ -1,4 +1,12 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "declaration.h" #include "declaration.h"
#include "../../hash_data/hash_data.h"
#include "../../hashmap/hashmap.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
#include "../../memory.h" #include "../../memory.h"
#include "../function/function.h" #include "../function/function.h"
@@ -8,11 +16,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_declaration(char *file, DArray *tokens, size_t *index) {
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
return (ParsedValueReturn){err, NULL};
}
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_DECLARATION; parsedValue->type = AST_DECLARATION;
DArray *declarations = checked_malloc(sizeof(DArray)); DArray *declarations = checked_malloc(sizeof(DArray));
@@ -23,81 +33,163 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
darray_push(declarations, &_declaration); darray_push(declarations, &_declaration);
ParsedSingleDeclaration *declaration = ParsedSingleDeclaration *declaration =
darray_get(declarations, declarations->size - 1); darray_get(declarations, declarations->size - 1);
bool isFunction=false; declaration->line = token->line;
declaration->column = token->column;
bool isFunction = false;
DArray parameters; DArray parameters;
declaration->from = parse_null(); declaration->from = parse_null();
if (token->type != TOKEN_IDENTIFIER) { if (token->type != TOKEN_IDENTIFIER) {
fprintf(stderr, "%s:%zu:%zu error: declaration requires an identifier\n", free_parsed(parsedValue);
file, token->line, token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "declaration requires an identifier"),
NULL};
} }
declaration->name = declaration->name =
strcpy(checked_malloc(strlen(token->value) + 1), token->value); strcpy(checked_malloc(strlen(token->value) + 1), token->value);
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_LPAREN) { if (token->type == TOKEN_LPAREN) {
isFunction = true; isFunction = true;
struct hashmap *parameters_hashmap = createHashmap();
darray_init(&parameters, sizeof(char *)); darray_init(&parameters, sizeof(char *));
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
hashmap_free(parameters_hashmap, NULL);
darray_free(&parameters, free_parameter);
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RPAREN) { if (token->type == TOKEN_RPAREN) {
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size) {
return parsedValue; hashmap_free(parameters_hashmap, NULL);
declaration->from = create_parsed_function(
declaration->name, parameters, declaration->from);
return (ParsedValueReturn){no_err, parsedValue};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
} else { } else {
while ((*index) < tokens->size) { while ((*index) < tokens->size) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type != TOKEN_IDENTIFIER) { if (token->type != TOKEN_IDENTIFIER) {
fprintf(stderr, darray_free(&parameters, free_parameter);
"%s:%zu:%zu error: parameter names need to start with a " free_parsed(parsedValue);
"letter or _, only use letters, digits, or _, and can't be " free(parsedValue);
"keywords.\n", return (ParsedValueReturn){
file, token->line, token->column); create_err(
exit(EXIT_FAILURE); token->line, token->column, token->length, file,
"Syntax Error",
"parameter names need to start with a letter or _, only "
"use letters, digits, or _, and can't be keywords."),
NULL};
} }
char *parameter_name = checked_malloc(strlen(token->value) + 1); uint64_t hash =
siphash64_bytes(token->value, token->length, siphash_key);
if (hashmap_lookup(parameters_hashmap, hash) != NULL) {
darray_free(&parameters, free_parameter);
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error",
"duplicate argument in function "
"definition"),
NULL};
}
char *parameter_name = checked_malloc(token->length + 1);
strcpy(parameter_name, token->value); strcpy(parameter_name, token->value);
hashmap_insert(parameters_hashmap, hash, parameter_name, (void *)1,
0);
darray_push(&parameters, &parameter_name); darray_push(&parameters, &parameter_name);
(*index)++; (*index)++;
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
hashmap_free(parameters_hashmap, NULL);
darray_free(&parameters, free_parameter);
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
hashmap_free(parameters_hashmap, NULL);
darray_free(&parameters, free_parameter);
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RPAREN) { if (token->type == TOKEN_RPAREN) {
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
break; break;
} else if (token->type != TOKEN_COMMA) { } else if (token->type != TOKEN_COMMA) {
fprintf(stderr, "%s:%zu:%zu error: expected comma\n", file, darray_free(&parameters, free_parameter);
token->line, token->column); free_parsed(parsedValue);
exit(EXIT_FAILURE); free(parsedValue);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected comma"),
NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
hashmap_free(parameters_hashmap, NULL);
darray_free(&parameters, free_parameter);
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
} }
} }
hashmap_free(parameters_hashmap, NULL);
} }
if (token->type == TOKEN_ASSIGN) { if (token->type == TOKEN_ASSIGN) {
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
ParsedValueReturn from = parse_token(file, tokens, index, true);
if (from.err.exists) {
if (isFunction) darray_free(&parameters, free_parameter);
free_parsed(parsedValue);
free(parsedValue);
return from;
}
free(declaration->from); free(declaration->from);
declaration->from = from.value;
declaration->from = parse_token(file, tokens, index, true);
if (!declaration->from) { if (!declaration->from) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, if (isFunction) darray_free(&parameters, free_parameter);
token->column); free_parsed(parsedValue);
exit(EXIT_FAILURE); free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected body"),
NULL};
} }
} }
if (isFunction) { if (isFunction) {
@@ -117,12 +209,22 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
break; break;
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
} }
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_string(void *ptr) { void free_string(void *ptr) {
@@ -133,9 +235,12 @@ void free_string(void *ptr) {
void free_single_declaration(void *ptr) { void free_single_declaration(void *ptr) {
ParsedSingleDeclaration *declaration = ptr; ParsedSingleDeclaration *declaration = ptr;
free(declaration->name); if (declaration->name)
free_parsed(declaration->from); free(declaration->name);
free(declaration->from); if (declaration->from) {
free_parsed(declaration->from);
free(declaration->from);
}
} }
void free_declaration(void *ptr) { void free_declaration(void *ptr) {

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef DECLARATION_H #ifndef DECLARATION_H
#define DECLARATION_H #define DECLARATION_H
#include "../parser.h" #include "../parser.h"
@@ -6,11 +12,12 @@
typedef struct { typedef struct {
char * name; char * name;
ParsedValue * from; ParsedValue * from;
uint64_t line;
uint64_t column;
} ParsedSingleDeclaration; } ParsedSingleDeclaration;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_declaration(char *file, DArray *tokens, ParsedValueReturn parse_declaration(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_declaration(void *ptr); void free_declaration(void *ptr);

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "dictionary.h" #include "dictionary.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
#include "../../memory.h" #include "../../memory.h"
@@ -7,7 +13,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_dictionary(char *file, DArray *tokens, size_t *index) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_DICTIONARY; parsedValue->type = AST_DICTIONARY;
DArray *dictionary = checked_malloc(sizeof(DArray)); DArray *dictionary = checked_malloc(sizeof(DArray));
@@ -15,41 +21,105 @@ ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) {
darray_init(dictionary, sizeof(ParsedValue)); darray_init(dictionary, sizeof(ParsedValue));
(*index)++; (*index)++;
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_RBRACE) { if (token->type != TOKEN_RBRACE) {
while (true) { while (true) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
size_t keyIndex = *index; size_t keyIndex = *index;
Token *keyToken = darray_get(tokens, *index); Token *keyToken = darray_get(tokens, *index);
ParsedValue *key; ParsedValueReturn key;
if (keyToken->type == TOKEN_IDENTIFIER) { if (keyToken->type == TOKEN_IDENTIFIER) {
(*index)++; (*index)++;
key = parse_string(keyToken, false); key = parse_string(keyToken, false);
} else { } else {
key = parse_token(file, tokens, index, true); key = parse_token(file, tokens, index, true);
} }
if (key.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return key;
} else if (!key.value) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected key"),
NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
ParsedValue *value; ParsedValueReturn value;
bool tobreak = false; bool tobreak = false;
switch (token->type) { switch (token->type) {
case TOKEN_COLON: case TOKEN_COLON:
(*index)++; (*index)++;
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
value = parse_token(file, tokens, index, true); value = parse_token(file, tokens, index, true);
if (value.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
free_parsed(key.value);
free(key.value);
return value;
} else if (!value.value) {
free_parsed(parsedValue);
free(parsedValue);
free_parsed(key.value);
free(key.value);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected value"),
NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
free_parsed(key.value);
free(key.value);
free_parsed(value.value);
free(value.value);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RBRACE) { if (token->type == TOKEN_RBRACE) {
tobreak = true; tobreak = true;
} else if (token->type != TOKEN_COMMA) { } else if (token->type != TOKEN_COMMA) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, free_parsed(parsedValue);
token->column); free(parsedValue);
exit(EXIT_FAILURE); free_parsed(key.value);
free(key.value);
free_parsed(value.value);
free(value.value);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected comma"),
NULL};
} }
break; break;
case TOKEN_RBRACE: case TOKEN_RBRACE:
@@ -59,21 +129,31 @@ ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) {
value = parse_token(file, tokens, &keyIndex, true); value = parse_token(file, tokens, &keyIndex, true);
break; break;
default: default:
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, free_parsed(parsedValue);
token->column); free(parsedValue);
exit(EXIT_FAILURE); free_parsed(key.value);
free(key.value);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "unexpected token"),
NULL};
} }
ParsedDictionaryEntry entry = {key, value}; ParsedDictionaryEntry entry = {key.value, value.value};
darray_push(dictionary, &entry); darray_push(dictionary, &entry);
if (tobreak) { if (tobreak) {
break; break;
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
} }
} }
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_dictionary_entry(void *ptr) { void free_dictionary_entry(void *ptr) {

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef DICTIONARY_H #ifndef DICTIONARY_H
#define DICTIONARY_H #define DICTIONARY_H
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
@@ -8,8 +14,7 @@ typedef struct {
ParsedValue * value; ParsedValue * value;
} ParsedDictionaryEntry; } ParsedDictionaryEntry;
ParsedValue *parse_dictionary(char *file, DArray *tokens, ParsedValueReturn parse_dictionary(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_parsed_dictionary(void *ptr); void free_parsed_dictionary(void *ptr);

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "dowrap.h" #include "dowrap.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
#include "../../memory.h" #include "../../memory.h"
@@ -24,7 +30,7 @@ void free_string_dowrap(void *ptr) {
free(str); free(str);
} }
ParsedValue *parse_dowrap(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_dowrap(char *file, DArray *tokens, size_t *index) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_DOWRAP; parsedValue->type = AST_DOWRAP;
DArray *dowrap_parsed = checked_malloc(sizeof(DArray)); DArray *dowrap_parsed = checked_malloc(sizeof(DArray));
@@ -32,74 +38,81 @@ ParsedValue *parse_dowrap(char *file, DArray *tokens, size_t *index) {
parsedValue->data = dowrap_parsed; parsedValue->data = dowrap_parsed;
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_NEW_LINE) { if (token->type != TOKEN_NEW_LINE) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, free_parsed(parsedValue);
token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
} }
size_t indent_depth = 0; size_t indent_depth = 0;
bool temp_indent_depth_toggle = false; bool has_body_started = false;
size_t temp_indent_depth = 0; bool inside_body = false;
bool pass = false; bool pass = false;
DArray dowrap_tokens; DArray dowrap_tokens;
darray_init(&dowrap_tokens, sizeof(Token)); darray_init(&dowrap_tokens, sizeof(Token));
DArray to_free; DArray to_free;
darray_init(&to_free, sizeof(char *)); darray_init(&to_free, sizeof(char *));
size_t temp_index_count = 0; size_t dowrap_index = *index;
size_t last_normal_token = dowrap_index-1;
while (!pass && ++(*index) < tokens->size) { while (!pass && ++dowrap_index < tokens->size) {
token = darray_get(tokens, *index); token = darray_get(tokens, dowrap_index);
switch (token->type) { switch (token->type) {
case TOKEN_INDENT:
temp_indent_depth_toggle = true;
if (dowrap_tokens.size == 0) {
indent_depth = strlen(token->value);
temp_indent_depth = indent_depth;
} else {
temp_indent_depth = strlen(token->value);
}
break;
case TOKEN_NEW_LINE: case TOKEN_NEW_LINE:
temp_indent_depth = 0;
temp_indent_depth_toggle = true;
darray_push(&dowrap_tokens, token); darray_push(&dowrap_tokens, token);
temp_index_count++; inside_body = false;
break; break;
default: case TOKEN_INDENT:
if (temp_indent_depth < indent_depth && temp_indent_depth_toggle) { if (!inside_body && !has_body_started) {
pass = true; indent_depth = token->length;
break; inside_body = true;
} } else if (indent_depth < token->length) {
if (temp_indent_depth > indent_depth) { size_t indent_amount = token->length - indent_depth;
size_t indent_amount = temp_indent_depth-indent_depth;
Token indent_token; Token indent_token;
indent_token.line = token->line; indent_token.line = token->line;
indent_token.column = token->column; indent_token.column = token->column;
indent_token.length = indent_amount;
indent_token.type = TOKEN_INDENT; indent_token.type = TOKEN_INDENT;
indent_token.value = repeat_space(indent_amount); indent_token.value = repeat_space(indent_amount);
darray_push(&dowrap_tokens, &indent_token); darray_push(&dowrap_tokens, &indent_token);
darray_push(&to_free, &indent_token.value); darray_push(&to_free, &indent_token.value);
inside_body = true;
} else if (indent_depth == token->length) {
inside_body = true;
} else if (indent_depth > token->length) {
inside_body = false;
} }
temp_indent_depth_toggle = false; break;
temp_indent_depth = 0; default:
temp_index_count=0; if (!inside_body) {
pass = true;
break;
}
last_normal_token = dowrap_index;
has_body_started = true;
darray_push(&dowrap_tokens, token); darray_push(&dowrap_tokens, token);
} }
} }
(*index)-=temp_index_count; *index = last_normal_token + 1;
for (size_t i = 0; i<temp_index_count;i++) { ArErr err = parser(file, dowrap_parsed, &dowrap_tokens, false);
darray_pop(&dowrap_tokens, NULL);
}
parser(file, dowrap_parsed, &dowrap_tokens, false);
darray_free(&dowrap_tokens, NULL); darray_free(&dowrap_tokens, NULL);
darray_free(&to_free, free_string_dowrap); darray_free(&to_free, free_string_dowrap);
return parsedValue; if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
return (ParsedValueReturn){no_err, parsedValue};
} }
void free_dowrap(void *ptr) { void free_dowrap(void *ptr) {

View File

@@ -1,11 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef DOWRAP_H #ifndef DOWRAP_H
#define DOWRAP_H #define DOWRAP_H
#include "../parser.h" #include "../parser.h"
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_dowrap(char *file, DArray *tokens, ParsedValueReturn parse_dowrap(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_dowrap(void *ptr); void free_dowrap(void *ptr);

View File

@@ -1,6 +1,11 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "function.h" #include "function.h"
#include "../../memory.h" #include "../../memory.h"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef FUNCTION_H #ifndef FUNCTION_H
#define FUNCTION_H #define FUNCTION_H
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
@@ -14,4 +20,6 @@ ParsedValue *create_parsed_function(char *name, DArray parameters,
void free_function(void *ptr); void free_function(void *ptr);
void free_parameter(void *ptr);
#endif // FUNCTION_H #endif // FUNCTION_H

View File

@@ -1,14 +1,34 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "if.h" #include "if.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
#include "../../memory.h" #include "../../memory.h"
#include "../parser.h" #include "../parser.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) { void free_conditional(void *ptr) {
ParsedConditional *conditional = ptr;
if (conditional->condition) {
free_parsed(conditional->condition);
free(conditional->condition);
}
free_parsed(conditional->content);
free(conditional->content);
}
ParsedValueReturn parse_if(char *file, DArray *tokens, size_t *index) {
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
return (ParsedValueReturn){err, NULL};
}
DArray *parsed_if = checked_malloc(sizeof(DArray)); DArray *parsed_if = checked_malloc(sizeof(DArray));
darray_init(parsed_if, sizeof(ParsedConditional)); darray_init(parsed_if, sizeof(ParsedConditional));
@@ -22,57 +42,117 @@ ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) {
if (!expect_conditional) { if (!expect_conditional) {
if (token->type != TOKEN_NEW_LINE) if (token->type != TOKEN_NEW_LINE)
break; // no more branches break; // no more branches
(*index)++; size_t current_index = *index;
skip_newlines_and_indents(tokens, index);
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
break; break;
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_ELSE || token->type == TOKEN_ELSE_IF) { if (token->type == TOKEN_ELSE || token->type == TOKEN_ELSE_IF) {
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){err, NULL};
}
} else { } else {
*index = current_index;
break; // no more branches break; // no more branches
} }
} }
ParsedValue *condition = NULL; ParsedValueReturn condition = {no_err, NULL};
if (token->type != TOKEN_ELSE) { if (token->type != TOKEN_ELSE) {
// Parse ( condition ) // Parse ( condition )
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type != TOKEN_LPAREN) { if (token->type != TOKEN_LPAREN) {
fprintf(stderr, "%s:%zu:%zu error: expected '(' after if\n", file, darray_free(parsed_if, free_conditional);
token->line, token->column); free(parsed_if);
exit(EXIT_FAILURE); return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected '(' after if"),
NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){err, NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
condition = parse_token(file, tokens, index, true); condition = parse_token(file, tokens, index, true);
if (condition.err.exists) {
darray_free(parsed_if, free_conditional);
free(parsed_if);
return condition;
} else if (!condition.value) {
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected condition"),
NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type != TOKEN_RPAREN) { if (token->type != TOKEN_RPAREN) {
fprintf(stderr, "%s:%zu:%zu error: missing closing ')' in condition\n", if (condition.value) {
file, token->line, token->column); free_parsed(condition.value);
exit(EXIT_FAILURE); free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "missing closing ')' in condition"),
NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){err, NULL};
}
} }
// Parse the body // Parse the body
ParsedValue *parsed_content = parse_token(file, tokens, index, false); ParsedValueReturn parsed_content = parse_token(file, tokens, index, false);
if (!parsed_content) { if (parsed_content.err.exists) {
fprintf(stderr, "%s:%zu:%zu error: expected body after condition\n", file, if (condition.value) {
token->line, token->column); free_parsed(condition.value);
exit(EXIT_FAILURE); free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return parsed_content;
} }
ParsedConditional conditional = {condition, parsed_content}; if (!parsed_content.value) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
}
ParsedConditional conditional = {condition.value, parsed_content.value};
darray_push(parsed_if, &conditional); darray_push(parsed_if, &conditional);
expect_conditional = expect_conditional =
@@ -98,17 +178,7 @@ ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) {
// printf(" - content value type: %d\n", cond->content->type); // printf(" - content value type: %d\n", cond->content->type);
// } // }
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
}
void free_conditional(void *ptr) {
ParsedConditional *conditional = ptr;
if (conditional->condition) {
free_parsed(conditional->condition);
free(conditional->condition);
}
free_parsed(conditional->content);
free(conditional->content);
} }
void free_parsed_if(void *ptr) { void free_parsed_if(void *ptr) {

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef iF_H #ifndef iF_H
#define iF_H #define iF_H
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
@@ -8,8 +14,7 @@ typedef struct {
ParsedValue *content; ParsedValue *content;
} ParsedConditional; } ParsedConditional;
ParsedValue *parse_if(char *file, DArray *tokens, ParsedValueReturn parse_if(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_parsed_if(void *ptr); void free_parsed_if(void *ptr);

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "list.h" #include "list.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
#include "../../memory.h" #include "../../memory.h"
@@ -6,7 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_list(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_list(char *file, DArray *tokens, size_t *index) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_LIST; parsedValue->type = AST_LIST;
DArray *list = checked_malloc(sizeof(DArray)); DArray *list = checked_malloc(sizeof(DArray));
@@ -14,31 +20,56 @@ ParsedValue *parse_list(char *file, DArray *tokens, size_t *index) {
darray_init(list, sizeof(ParsedValue)); darray_init(list, sizeof(ParsedValue));
(*index)++; (*index)++;
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_RBRACKET) { if (token->type != TOKEN_RBRACKET) {
while (true) { while (true) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
ParsedValue *parsedValue = parse_token(file, tokens, index, true); ParsedValueReturn parsedItem = parse_token(file, tokens, index, true);
darray_push(list, parsedValue); if (parsedItem.err.exists) {
free(parsedValue); free_parsed(parsedValue);
error_if_finished(file, tokens, index); free(parsedValue);
return parsedItem;
}
darray_push(list, parsedItem.value);
free(parsedItem.value);
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RBRACKET) { if (token->type == TOKEN_RBRACKET) {
break; break;
} else if (token->type != TOKEN_COMMA) { } else if (token->type != TOKEN_COMMA) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, free_parsed(parsedValue);
token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){create_err(token->line, token->column, token->length, file, "Syntax Error", "expected comma"), NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
} }
} }
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parsed_list(void *ptr) { void free_parsed_list(void *ptr) {

View File

@@ -1,10 +1,15 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LIST_H #ifndef LIST_H
#define LIST_H #define LIST_H
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
#include "../parser.h" #include "../parser.h"
ParsedValue *parse_list(char *file, DArray *tokens, ParsedValueReturn parse_list(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_parsed_list(void *ptr); void free_parsed_list(void *ptr);

View File

@@ -1,22 +1,25 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "literals.h" #include "literals.h"
#include "../parser.h" #include "../parser.h"
#include <stdbool.h> #include <stdbool.h>
#include "../../memory.h" #include "../../memory.h"
static bool true_value = true;
static bool false_value = false;
ParsedValue * parse_true(){ ParsedValue * parse_true(){
ParsedValue * parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue * parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_BOOLEAN; parsedValue->type = AST_BOOLEAN;
parsedValue->data = &true_value; parsedValue->data = (void*)true;
return parsedValue; return parsedValue;
}; };
ParsedValue * parse_false(){ ParsedValue * parse_false(){
ParsedValue * parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue * parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_BOOLEAN; parsedValue->type = AST_BOOLEAN;
parsedValue->data = &false_value; parsedValue->data = (void*)false;
return parsedValue; return parsedValue;
}; };

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LITERALS_H #ifndef LITERALS_H
#define LITERALS_H #define LITERALS_H
#include "../parser.h" #include "../parser.h"

50
src/parser/not/not.c Normal file
View File

@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "not.h"
#include "../../lexer/token.h"
#include "../../memory.h"
#include "../parser.h"
#include <stdio.h>
ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index) {
bool invert = true;
(*index)++;
while (tokens->size > *index) {
Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_EXCLAMATION) {
ParsedValueReturn value =
parse_token_full(file, tokens, index, true, false);
if (value.err.exists) {
return value;
} else if (!value.value) {
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected value"),
NULL};
}
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedToBool *parsedToBool = checked_malloc(sizeof(ParsedToBool));
parsedToBool->value = value.value;
parsedToBool->invert = invert;
parsedValue->data = parsedToBool;
parsedValue->type = AST_TO_BOOL;
return (ParsedValueReturn){no_err, parsedValue};
}
invert = !invert;
(*index)++;
}
ArErr err = error_if_finished(file, tokens, index);
return (ParsedValueReturn){err, NULL};
}
void free_not(void *ptr) {
ParsedValue *parsedValue = ptr;
ParsedToBool *parsedToBool = parsedValue->data;
free_parsed(parsedToBool->value);
free(parsedToBool->value);
free(parsedToBool);
}

20
src/parser/not/not.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef NOT_H
#define NOT_H
#include "../parser.h"
typedef struct {
bool invert;
ParsedValue*value;
} ParsedToBool;
ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index);
void free_not(void *ptr);
#endif // NOT_H

View File

@@ -1,158 +1,193 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "number.h" #include "number.h"
#include "../../lexer/token.h"
#include "../parser.h"
#include "../../memory.h" #include "../../memory.h"
#include <ctype.h>
#include <gmp.h> #include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
// #include <ctype.h>
int parse_exponent(const char *exp_str, long *exp_val) {
char *endptr;
long val = strtol(exp_str, &endptr, 10);
if (*endptr != '\0') {
// exponent contains invalid chars or decimal point → reject
return -1;
}
*exp_val = val;
return 0;
}
// int parse_exponent(const char *exp_str, long *exp_val) { int mpq_set_decimal_str_exp(mpq_t r, const char *str, size_t len) {
// char *endptr; // Skip leading whitespace
// long val = strtol(exp_str, &endptr, 10); while (isspace(*str))
// if (*endptr != '\0') { str++;
// // exponent contains invalid chars or decimal point → reject
// return -1;
// }
// *exp_val = val;
// return 0;
// }
// int mpq_set_decimal_str_exp(mpq_t r, const char *str) { // Handle sign
// // Skip leading whitespace int negative = 0;
// while (isspace(*str)) str++; if (*str == '-') {
negative = 1;
str++;
} else if (*str == '+') {
str++;
}
// // Handle sign // Copy input to a buffer for manipulation
// int negative = 0; char *buf = malloc(len + 1);
// if (*str == '-') { if (!buf)
// negative = 1; return -1;
// str++; memcpy(buf, str, len);
// } else if (*str == '+') { buf[len] = '\0';
// str++;
// }
// // Copy input to a buffer for manipulation // Find 'e' or 'E'
// size_t len = strlen(str); char *e_ptr = strchr(buf, 'e');
// char *buf = malloc(len + 1); if (!e_ptr)
// if (!buf) return -1; e_ptr = strchr(buf, 'E');
// strcpy(buf, str);
// // Find 'e' or 'E' char *exp_str = NULL;
// char *e_ptr = strchr(buf, 'e'); if (e_ptr) {
// if (!e_ptr) e_ptr = strchr(buf, 'E'); *e_ptr = '\0';
exp_str = e_ptr + 1;
}
// char *exp_str = NULL; // Validate decimal part (digits and one dot)
// if (e_ptr) { int dot_count = 0;
// *e_ptr = '\0'; for (char *p = buf; *p; p++) {
// exp_str = e_ptr + 1; if (*p == '.') {
// } if (++dot_count > 1) {
free(buf);
return -1;
}
continue;
}
if (!isdigit((unsigned char)*p)) {
free(buf);
return -1;
}
}
// // Validate decimal part (digits and one dot) // Extract integer and fractional parts
// int dot_count = 0; char *dot = strchr(buf, '.');
// for (char *p = buf; *p; p++) { size_t int_len = dot ? (size_t)(dot - buf) : strlen(buf);
// if (*p == '.') { size_t frac_len = dot ? strlen(dot + 1) : 0;
// if (++dot_count > 1) { free(buf); return -1; }
// continue;
// }
// if (!isdigit((unsigned char)*p)) { free(buf); return -1; }
// }
// // Extract integer and fractional parts // Validate exponent if present
// char *dot = strchr(buf, '.'); int exp_negative = 0;
// size_t int_len = dot ? (size_t)(dot - buf) : strlen(buf); long exp_val = 0;
// size_t frac_len = dot ? strlen(dot + 1) : 0; if (exp_str) {
// Skip leading spaces in exponent (not in regex but safe)
while (isspace(*exp_str))
exp_str++;
// // Validate exponent if present if (*exp_str == '-') {
// int exp_negative = 0; exp_negative = 1;
// long exp_val = 0; exp_str++;
// if (exp_str) { } else if (*exp_str == '+') {
// // Skip leading spaces in exponent (not in regex but safe) exp_str++;
// while (isspace(*exp_str)) exp_str++; }
// if (*exp_str == '-') { if (!isdigit((unsigned char)*exp_str)) {
// exp_negative = 1; free(buf);
// exp_str++; return -1;
// } else if (*exp_str == '+') { }
// exp_str++;
// }
// if (!isdigit((unsigned char)*exp_str)) { char *endptr;
// free(buf); exp_val = strtol(exp_str, &endptr, 10);
// return -1; if (*endptr != '\0') {
// } free(buf);
return -1;
}
// char *endptr; if (endptr - exp_str > 11) {
// exp_val = strtol(exp_str, &endptr, 10); free(buf);
// if (*endptr != '\0') { return -1;
// free(buf); }
// return -1; if (exp_negative)
// } exp_val = -exp_val;
// if (exp_negative) exp_val = -exp_val; }
// }
// // Build numerator string (integer part + fractional part) // Build numerator string (integer part + fractional part)
// size_t num_len = int_len + frac_len; size_t num_len = int_len + frac_len;
// if (num_len == 0) { free(buf); return -1; } if (num_len == 0) {
free(buf);
return -1;
}
// char *num_str = malloc(num_len + 1); char *num_str = malloc(num_len + 1);
// if (!num_str) { free(buf); return -1; } if (!num_str) {
free(buf);
return -1;
}
// if (int_len > 0) memcpy(num_str, buf, int_len); if (int_len > 0)
// if (frac_len > 0) memcpy(num_str + int_len, dot + 1, frac_len); memcpy(num_str, buf, int_len);
// num_str[num_len] = '\0'; if (frac_len > 0)
memcpy(num_str + int_len, dot + 1, frac_len);
num_str[num_len] = '\0';
// // Calculate denominator exponent considering exponent part // Calculate denominator exponent considering exponent part
// long denom_exp = frac_len - exp_val; long denom_exp = frac_len - exp_val;
// mpz_t numerator, denominator; mpz_t numerator, denominator;
// mpz_init(numerator); mpz_init(numerator);
// mpz_init(denominator); mpz_init(denominator);
// if (mpz_set_str(numerator, num_str, 10) != 0) { if (mpz_set_str(numerator, num_str, 10) != 0) {
// free(num_str); free(num_str);
// free(buf); free(buf);
// mpz_clear(numerator); mpz_clear(numerator);
// mpz_clear(denominator); mpz_clear(denominator);
// return -1; return -1;
// } }
// free(num_str); free(num_str);
// free(buf); free(buf);
// if (denom_exp >= 0) { if (denom_exp >= 0) {
// mpz_ui_pow_ui(denominator, 10, (unsigned long)denom_exp); mpz_ui_pow_ui(denominator, 10, (unsigned long)denom_exp);
// } else { } else {
// // denom_exp < 0 means multiply numerator by 10^(-denom_exp) mpz_set_ui(denominator, 1);
// mpz_ui_pow_ui(denominator, 10, 0);
// mpz_ui_pow_ui(numerator, 10, (unsigned long)(-denom_exp));
// }
// if (denom_exp < 0) { mpz_t temp;
// mpz_t temp; mpz_init(temp);
// mpz_init(temp); mpz_ui_pow_ui(temp, 10, (unsigned long)(-denom_exp));
// mpz_ui_pow_ui(temp, 10, (unsigned long)(-denom_exp)); mpz_mul(numerator, numerator, temp);
// mpz_mul(numerator, numerator, temp); mpz_clear(temp);
// mpz_clear(temp); }
// mpz_set_ui(denominator, 1);
// }
// mpq_set_num(r, numerator); mpq_set_num(r, numerator);
// mpq_set_den(r, denominator); mpq_set_den(r, denominator);
// mpq_canonicalize(r); mpq_canonicalize(r);
// if (negative) mpq_neg(r, r); if (negative)
mpq_neg(r, r);
// mpz_clear(numerator); mpz_clear(numerator);
// mpz_clear(denominator); mpz_clear(denominator);
// return 0; return 0;
// } }
ParsedValue *parse_number(Token *token) { ParsedValueReturn parse_number(Token *token, char *path) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_NUMBER; parsedValue->type = AST_NUMBER;
parsedValue->data = strdup(token->value); mpq_t *r_ptr = malloc(sizeof(mpq_t));
return parsedValue; mpq_init(*r_ptr);
int err = mpq_set_decimal_str_exp(*r_ptr, token->value, token->length);
if (err) {
mpq_clear(*r_ptr);
free(r_ptr);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, path, "Parsing Error",
"Unable to parse number"),
NULL};
}
parsedValue->data = r_ptr;
return (ParsedValueReturn){no_err, parsedValue};
} }

View File

@@ -1,9 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef NUMBER_H #ifndef NUMBER_H
#define NUMBER_H #define NUMBER_H
#include "../parser.h" #include "../parser.h"
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue * parse_number(Token * token); ParsedValueReturn parse_number(Token *token, char*path);
int mpq_set_decimal_str_exp(mpq_t r, const char *str, size_t len);
#endif // NUMBER_H #endif // NUMBER_H

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "operations.h" #include "operations.h"
#include "../../memory.h" #include "../../memory.h"
#include "../parser.h" #include "../parser.h"
@@ -8,60 +14,66 @@
ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) { ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
if (to_operate_on->size == 1) { if (to_operate_on->size == 1) {
return *((ParsedValue*)darray_get(to_operate_on, 0)); return *((ParsedValue *)darray_get(to_operate_on, 0));
} }
TokenType operation = 0; ArTokenType operation_type = 0;
Token operation = {};
DArray positions; DArray positions;
for (size_t i = 0; i < operations->size; i++) { for (size_t i = 0; i < operations->size; i++) {
TokenType *current_operation = darray_get(operations, i); Token *current_operation = darray_get(operations, i);
if (operation < *current_operation) { if (operation_type < current_operation->type) {
if (operation != 0) { if (operation_type != 0) {
darray_free(&positions, NULL); darray_free(&positions, NULL);
} }
operation_type = current_operation->type;
operation = *current_operation; operation = *current_operation;
darray_init(&positions, sizeof(size_t)); darray_init(&positions, sizeof(size_t));
} }
darray_push(&positions, &i); if (operation_type == current_operation->type) {
darray_push(&positions, &i);
}
} }
ParsedValue parsedValue; ParsedValue parsedValue;
parsedValue.type = AST_OPERATION; parsedValue.type = AST_OPERATION;
ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation)); ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation));
parsedValue.data = operationStruct; parsedValue.data = operationStruct;
operationStruct->operation = operation; operationStruct->operation = operation_type;
operationStruct->line = operation.line;
operationStruct->column = operation.column;
operationStruct->length = operation.length;
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue)); darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
size_t last_position = 0;
size_t to_operate_on_last_position = 0; size_t to_operate_on_last_position = 0;
for (size_t i = 0; i < positions.size; i++) { for (size_t i = 0; i < positions.size; i++) {
size_t *position = darray_get(&positions, i); size_t *position = darray_get(&positions, i);
DArray to_operate_on_slice = darray_slice( DArray to_operate_on_slice = darray_slice(
to_operate_on, to_operate_on_last_position, (*position) + 1); to_operate_on, to_operate_on_last_position, (*position) + 1);
DArray operations_slice = DArray operations_slice =
darray_slice(operations, last_position, *position); darray_slice(operations, to_operate_on_last_position, (*position));
ParsedValue result = convert_to_operation(&to_operate_on_slice, &operations_slice); ParsedValue result =
darray_push(&operationStruct->to_operate_on, convert_to_operation(&to_operate_on_slice, &operations_slice);
&result); darray_push(&operationStruct->to_operate_on, &result);
last_position = (*position);
to_operate_on_last_position = (*position) + 1; to_operate_on_last_position = (*position) + 1;
} }
DArray to_operate_on_slice = DArray to_operate_on_slice = darray_slice(
darray_slice(to_operate_on, to_operate_on_last_position, to_operate_on->size); to_operate_on, to_operate_on_last_position, to_operate_on->size);
DArray operations_slice = darray_slice(operations, last_position, operations->size); DArray operations_slice =
ParsedValue result =convert_to_operation(&to_operate_on_slice, &operations_slice); darray_slice(operations, to_operate_on_last_position, operations->size);
darray_push(&operationStruct->to_operate_on, ParsedValue result =
&result); convert_to_operation(&to_operate_on_slice, &operations_slice);
darray_push(&operationStruct->to_operate_on, &result);
darray_free(&positions, NULL); darray_free(&positions, NULL);
return parsedValue; return parsedValue;
} }
ParsedValue *parse_operations(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_operations(char *file, DArray *tokens, size_t *index,
ParsedValue *first_parsed_value) { ParsedValue *first_parsed_value) {
DArray to_operate_on; DArray to_operate_on;
darray_init(&to_operate_on, sizeof(ParsedValue)); darray_init(&to_operate_on, sizeof(ParsedValue));
darray_push(&to_operate_on, first_parsed_value); darray_push(&to_operate_on, first_parsed_value);
free(first_parsed_value); free(first_parsed_value);
DArray operations; DArray operations;
darray_init(&operations, sizeof(TokenType)); darray_init(&operations, sizeof(Token));
while (tokens->size > *index) { while (tokens->size > *index) {
bool to_break = false; bool to_break = false;
@@ -74,20 +86,37 @@ ParsedValue *parse_operations(char *file, DArray *tokens, size_t *index,
} }
if (to_break) if (to_break)
break; break;
darray_push(&operations, &token->type); darray_push(&operations, token);
(*index)++; (*index)++;
error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
ParsedValue *parsedValue = if (err.exists) {
darray_free(&to_operate_on, free_parsed);
darray_free(&operations, NULL);
return (ParsedValueReturn){err, NULL};
}
ParsedValueReturn parsedValue =
parse_token_full(file, tokens, index, true, false); parse_token_full(file, tokens, index, true, false);
darray_push(&to_operate_on, parsedValue); if (parsedValue.err.exists) {
free(parsedValue); darray_free(&to_operate_on, free_parsed);
darray_free(&operations, NULL);
return parsedValue;
} else if (!parsedValue.value) {
darray_free(&to_operate_on, free_parsed);
darray_free(&operations, NULL);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected value"),
NULL};
}
darray_push(&to_operate_on, parsedValue.value);
free(parsedValue.value);
} }
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedValue output = convert_to_operation(&to_operate_on, &operations); ParsedValue output = convert_to_operation(&to_operate_on, &operations);
memcpy(parsedValue, &output,sizeof(ParsedValue)); memcpy(parsedValue, &output, sizeof(ParsedValue));
darray_free(&to_operate_on, NULL); darray_free(&to_operate_on, NULL);
darray_free(&operations, NULL); darray_free(&operations, NULL);
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_operation(void *ptr) { void free_operation(void *ptr) {

View File

@@ -1,14 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef OPERATIONS_H #ifndef OPERATIONS_H
#define OPERATIONS_H #define OPERATIONS_H
#include "../parser.h" #include "../parser.h"
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
typedef struct { typedef struct {
TokenType operation; ArTokenType operation;
DArray to_operate_on; // ParsedValue[] DArray to_operate_on; // ParsedValue[]
size_t line;
size_t column;
size_t length;
} ParsedOperation; } ParsedOperation;
ParsedValue *parse_operations(char*file,DArray *tokens, size_t * index, ParsedValue * first_parsed_value); ParsedValueReturn parse_operations(char *file, DArray *tokens, size_t *index,
ParsedValue *first_parsed_value);
void free_operation(void *ptr); void free_operation(void *ptr);

View File

@@ -0,0 +1,105 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "parentheses-and-anonymous-function.h"
#include "../../memory.h"
#include "../assignable/identifier/identifier.h"
#include "../function/function.h"
#include <stddef.h>
#include <string.h>
ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index) {
(*index)++;
skip_newlines_and_indents(tokens, index);
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
// darray_free(&list, free_parsed);
return (ParsedValueReturn){err, NULL};
}
DArray list;
darray_init(&list, sizeof(ParsedValue));
Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_RPAREN) {
while (*index < tokens->size) {
ParsedValueReturn parsedItem = parse_token(file, tokens, index, true);
if (parsedItem.err.exists) {
darray_free(&list, free_parsed);
return parsedItem;
}
darray_push(&list, parsedItem.value);
free(parsedItem.value);
skip_newlines_and_indents(tokens, index);
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
darray_free(&list, free_parsed);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index);
if (token->type == TOKEN_RPAREN) {
break;
} else if (token->type != TOKEN_COMMA) {
darray_free(&list, free_parsed);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected comma"),
NULL};
}
(*index)++;
skip_newlines_and_indents(tokens, index);
err = error_if_finished(file, tokens, index);
if (err.exists) {
darray_free(&list, free_parsed);
return (ParsedValueReturn){err, NULL};
}
}
}
(*index)++;
if (*index < tokens->size) {
token = darray_get(tokens, *index);
if (token->type == TOKEN_ASSIGN) {
(*index)++;
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
darray_free(&list, free_parsed);
return (ParsedValueReturn){err, NULL};
}
DArray parameters;
darray_init(&parameters, sizeof(char *));
for (size_t i = 0; i < list.size; i++) {
ParsedValue *item = darray_get(&list, i);
if (item->type != AST_IDENTIFIER) {
darray_free(&list, free_parsed);
darray_free(&parameters, free_parameter);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected identifier"),
NULL};
}
char *param = strdup(((ParsedIdentifier *)item->data)->name);
darray_push(&parameters, &param);
}
darray_free(&list, free_parsed);
ParsedValueReturn parsedBody = parse_token(file, tokens, index, true);
if (parsedBody.err.exists) {
darray_free(&parameters, free_parameter);
return parsedBody;
}
return (ParsedValueReturn){
no_err,
create_parsed_function("anonymous", parameters, parsedBody.value)};
}
}
if (list.size != 1) {
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected 1 body"),
NULL};
}
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
memcpy(parsedValue, darray_get(&list, 0), sizeof(ParsedValue));
darray_free(&list, NULL);
return (ParsedValueReturn){no_err, parsedValue};
}

View File

@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef parentheses_and_anonymous_function_H
#define parentheses_and_anonymous_function_H
#include "../parser.h"
#include "../../lexer/token.h"
ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index);
#endif // parentheses_and_anonymous_function_H

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "parser.h" #include "parser.h"
#include "../dynamic_array/darray.h" #include "../dynamic_array/darray.h"
#include "../lexer/token.h" #include "../lexer/token.h"
@@ -5,6 +11,7 @@
#include "assignable/assign/assign.h" #include "assignable/assign/assign.h"
#include "assignable/call/call.h" #include "assignable/call/call.h"
#include "assignable/identifier/identifier.h" #include "assignable/identifier/identifier.h"
#include "assignable/item/item.h"
#include "declaration/declaration.h" #include "declaration/declaration.h"
#include "dictionary/dictionary.h" #include "dictionary/dictionary.h"
#include "dowrap/dowrap.h" #include "dowrap/dowrap.h"
@@ -14,7 +21,11 @@
#include "literals/literals.h" #include "literals/literals.h"
#include "number/number.h" #include "number/number.h"
#include "operations/operations.h" #include "operations/operations.h"
#include "parentheses-and-anonymous-function/parentheses-and-anonymous-function.h"
#include "return/return.h"
#include "string/string.h" #include "string/string.h"
#include "not/not.h"
#include "while/while.h"
#include <gmp.h> #include <gmp.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@@ -25,15 +36,16 @@
const char *ValueTypeNames[] = { const char *ValueTypeNames[] = {
"string", "assign", "identifier", "number", "if statement", "string", "assign", "identifier", "number", "if statement",
"access", "call", "declaration", "null", "boolean", "access", "call", "declaration", "null", "boolean",
"do wrap", "operations", "list", "dictionary", "function"}; "do wrap", "operations", "list", "dictionary", "function",
"return", "while loop", "not"};
void error_if_finished(char *file, DArray *tokens, size_t *index) { ArErr error_if_finished(char *file, DArray *tokens, size_t *index) {
if ((*index) >= tokens->size) { if ((*index) >= tokens->size) {
Token *token = darray_get(tokens, tokens->size - 1); Token *token = darray_get(tokens, tokens->size - 1);
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, return create_err(token->line, token->column, token->length, file,
token->column); "Syntax Error", "more code was expected");
exit(EXIT_FAILURE);
} }
return no_err;
} }
size_t skip_newlines_and_indents(DArray *tokens, size_t *index) { size_t skip_newlines_and_indents(DArray *tokens, size_t *index) {
@@ -54,16 +66,22 @@ size_t skip_newlines_and_indents(DArray *tokens, size_t *index) {
return count; return count;
} }
ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
bool inline_flag, bool process_operations) { bool inline_flag, bool process_operations) {
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
ParsedValue *output = NULL; ParsedValueReturn output;
if (!inline_flag) { if (!inline_flag) {
switch (token->type) { switch (token->type) {
case TOKEN_IF: case TOKEN_IF:
return parse_if(file, tokens, index); return parse_if(file, tokens, index);
case TOKEN_WHILE:
return parse_while(file, tokens, index);
case TOKEN_RETURN:
return parse_return(file, tokens, index);
case TOKEN_LET:
return parse_declaration(file, tokens, index);
default: default:
break; break;
}; };
@@ -71,15 +89,15 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
switch (token->type) { switch (token->type) {
case TOKEN_TRUE: case TOKEN_TRUE:
(*index)++; (*index)++;
output = parse_true(); output = (ParsedValueReturn){no_err, parse_true()};
break; break;
case TOKEN_FALSE: case TOKEN_FALSE:
(*index)++; (*index)++;
output = parse_false(); output = (ParsedValueReturn){no_err, parse_false()};
break; break;
case TOKEN_NULL: case TOKEN_NULL:
(*index)++; (*index)++;
output = parse_null(); output = (ParsedValueReturn){no_err, parse_null()};
break; break;
case TOKEN_STRING: case TOKEN_STRING:
(*index)++; (*index)++;
@@ -87,28 +105,28 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
break; break;
case TOKEN_NEW_LINE: case TOKEN_NEW_LINE:
(*index)++; (*index)++;
return NULL; return (ParsedValueReturn){no_err, NULL};
case TOKEN_INDENT: case TOKEN_INDENT:;
Token *token_indent = token;
if (strlen(token->value) > 0 && (*index + 1) < tokens->size) { if (strlen(token->value) > 0 && (*index + 1) < tokens->size) {
token = darray_get(tokens, (*index) + 1); token = darray_get(tokens, (*index) + 1);
if (token->type != TOKEN_NEW_LINE) { if (token->type != TOKEN_NEW_LINE) {
fprintf(stderr, "%s:%zu:%zu error: invalid indentation\n", file, return (ParsedValueReturn){
token->line, token->column); create_err(token_indent->line, token_indent->column,
exit(EXIT_FAILURE); token_indent->length, file, "Syntax Error",
"unexpected indent"),
NULL};
} }
} }
(*index)++; (*index)++;
return NULL; return (ParsedValueReturn){no_err, NULL};
case TOKEN_IDENTIFIER: case TOKEN_IDENTIFIER:
(*index)++; (*index)++;
output = parse_identifier(token); output = parse_identifier(token);
break; break;
case TOKEN_NUMBER: case TOKEN_NUMBER:
(*index)++; (*index)++;
output = parse_number(token); output = parse_number(token, file);
break;
case TOKEN_LET:
output = parse_declaration(file, tokens, index);
break; break;
case TOKEN_DO: case TOKEN_DO:
output = parse_dowrap(file, tokens, index); output = parse_dowrap(file, tokens, index);
@@ -116,40 +134,45 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
case TOKEN_LBRACKET: case TOKEN_LBRACKET:
output = parse_list(file, tokens, index); output = parse_list(file, tokens, index);
break; break;
case TOKEN_LPAREN:
output = parse_parentheses(file, tokens, index);
break;
case TOKEN_LBRACE: case TOKEN_LBRACE:
output = parse_dictionary(file, tokens, index); output = parse_dictionary(file, tokens, index);
break; break;
case TOKEN_EXCLAMATION:
output = parse_not(file, tokens, index);
break;
default: default:
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, return (ParsedValueReturn){create_err(token->line, token->column,
token->column); token->length, file, "Syntax Error",
exit(EXIT_FAILURE); "unexpected token"),
NULL};
} }
// LHS required // LHS required
bool passed = false; bool passed = false;
while (!passed && (*index) < tokens->size) { while (!passed && (*index) < tokens->size) {
if (output.err.exists) {
return output;
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
switch (token->type) { switch (token->type) {
case TOKEN_ASSIGN: case TOKEN_ASSIGN:
case TOKEN_ASSIGN_CARET: output = parse_assign(file, tokens, output.value, index);
case TOKEN_ASSIGN_FLOORDIV:
case TOKEN_ASSIGN_MINUS:
case TOKEN_ASSIGN_MODULO:
case TOKEN_ASSIGN_PLUS:
case TOKEN_ASSIGN_SLASH:
case TOKEN_ASSIGN_STAR:
output = parse_assign(file, tokens, output, index);
break; break;
case TOKEN_LPAREN: case TOKEN_LPAREN:
output = parse_call(file, tokens, index, output); output = parse_call(file, tokens, index, output.value);
break; break;
case TOKEN_DOT: case TOKEN_DOT:
output = parse_access(file, tokens, index, output.value);
break;
case TOKEN_LBRACKET: case TOKEN_LBRACKET:
output = parse_access(file, tokens, index, output); output = parse_item_access(file, tokens, index, output.value);
break; break;
SWITCH_OPERATIONS SWITCH_OPERATIONS
if (process_operations) { if (process_operations) {
output = parse_operations(file, tokens, index, output); output = parse_operations(file, tokens, index, output.value);
break; break;
} }
/* fall through */ /* fall through */
@@ -161,31 +184,34 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
return output; return output;
} }
ParsedValue *parse_token(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_token(char *file, DArray *tokens, size_t *index,
bool inline_flag) { bool inline_flag) {
return parse_token_full(file, tokens, index, inline_flag, true); return parse_token_full(file, tokens, index, inline_flag, true);
} }
void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) { ArErr parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) {
size_t index = 0; size_t index = 0;
bool expecting_new_line = false; bool expecting_new_line = false;
while (index < tokens->size) { while (index < tokens->size) {
size_t old_index = index; size_t old_index = index;
ParsedValue *parsed_code = parse_token(file, tokens, &index, inline_flag); ParsedValueReturn parsed_code =
if (parsed_code) { parse_token(file, tokens, &index, inline_flag);
if (parsed_code.err.exists) {
return parsed_code.err;
} else if (parsed_code.value) {
if (expecting_new_line) { if (expecting_new_line) {
Token *token = darray_get(tokens, old_index); Token *token = darray_get(tokens, old_index);
fprintf(stderr, "%s:%zu:%zu error: expected a new line\n", file, return create_err(token->line, token->column, token->length, file,
token->line, token->column); "Syntax Error", "invalid syntax");
exit(EXIT_FAILURE);
} }
expecting_new_line = true; expecting_new_line = true;
darray_push(parsed, parsed_code); darray_push(parsed, parsed_code.value);
free(parsed_code); free(parsed_code.value);
} else { } else {
expecting_new_line = false; expecting_new_line = false;
} }
} }
return no_err;
} }
void free_parsed(void *ptr) { void free_parsed(void *ptr) {
@@ -197,7 +223,10 @@ void free_parsed(void *ptr) {
ParsedValue *parsed = ptr; ParsedValue *parsed = ptr;
switch (parsed->type) { switch (parsed->type) {
case AST_IDENTIFIER: case AST_IDENTIFIER:
free_identifier(parsed);
break;
case AST_NUMBER: case AST_NUMBER:
mpq_clear(*(mpq_t *)parsed->data);
free(parsed->data); free(parsed->data);
break; break;
case AST_STRING: case AST_STRING:
@@ -215,12 +244,18 @@ void free_parsed(void *ptr) {
case AST_ACCESS: case AST_ACCESS:
free_parse_access(parsed); free_parse_access(parsed);
break; break;
case AST_ITEM_ACCESS:
free_parse_item_access(parsed);
break;
case AST_NULL: case AST_NULL:
case AST_BOOLEAN: case AST_BOOLEAN:
break; break;
case AST_IF: case AST_IF:
free_parsed_if(parsed); free_parsed_if(parsed);
break; break;
case AST_WHILE:
free_parsed_while(parsed);
break;
case AST_OPERATION: case AST_OPERATION:
free_operation(parsed); free_operation(parsed);
break; break;
@@ -235,5 +270,12 @@ void free_parsed(void *ptr) {
break; break;
case AST_FUNCTION: case AST_FUNCTION:
free_function(parsed); free_function(parsed);
break;
case AST_RETURN:
free_parsed_return(parsed);
break;
case AST_TO_BOOL:
free_not(parsed);
break;
} }
} }

View File

@@ -1,27 +1,35 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef PARSER_H #ifndef PARSER_H
#define PARSER_H #define PARSER_H
#include "../dynamic_array/darray.h" #include "../dynamic_array/darray.h"
#include "../err.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#define SWITCH_OPERATIONS case TOKEN_AND:\ #define SWITCH_OPERATIONS \
case TOKEN_OR:\ case TOKEN_AND: \
case TOKEN_NOT_IN:\ case TOKEN_OR: \
case TOKEN_IN:\ case TOKEN_NOT_IN: \
case TOKEN_LE:\ case TOKEN_IN: \
case TOKEN_GE:\ case TOKEN_LE: \
case TOKEN_LT:\ case TOKEN_GE: \
case TOKEN_GT:\ case TOKEN_LT: \
case TOKEN_NE:\ case TOKEN_GT: \
case TOKEN_EQ:\ case TOKEN_NE: \
case TOKEN_PLUS:\ case TOKEN_EQ: \
case TOKEN_MINUS:\ case TOKEN_PLUS: \
case TOKEN_MODULO:\ case TOKEN_MINUS: \
case TOKEN_STAR:\ case TOKEN_MODULO: \
case TOKEN_FLOORDIV:\ case TOKEN_STAR: \
case TOKEN_SLASH:\ case TOKEN_FLOORDIV: \
case TOKEN_CARET: case TOKEN_SLASH: \
case TOKEN_CARET:
typedef struct LinkedList LinkedList; typedef struct LinkedList LinkedList;
@@ -32,6 +40,7 @@ typedef enum {
AST_NUMBER, AST_NUMBER,
AST_IF, AST_IF,
AST_ACCESS, AST_ACCESS,
AST_ITEM_ACCESS,
AST_CALL, AST_CALL,
AST_DECLARATION, AST_DECLARATION,
AST_NULL, AST_NULL,
@@ -40,27 +49,35 @@ typedef enum {
AST_OPERATION, AST_OPERATION,
AST_LIST, AST_LIST,
AST_DICTIONARY, AST_DICTIONARY,
AST_FUNCTION AST_FUNCTION,
AST_RETURN,
AST_WHILE,
AST_TO_BOOL
} ValueType; } ValueType;
extern const char* ValueTypeNames[]; extern const char *ValueTypeNames[];
typedef struct { typedef struct {
ValueType type; ValueType type;
void *data; void *data;
} ParsedValue; } ParsedValue;
void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag); typedef struct {
ArErr err;
ParsedValue *value;
} ParsedValueReturn;
ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, ArErr parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag);
bool inline_flag, bool process_operations);
ParsedValue *parse_token(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
bool inline_flag, bool process_operations);
ParsedValueReturn parse_token(char *file, DArray *tokens, size_t *index,
bool inline_flag); bool inline_flag);
void free_parsed(void *ptr); void free_parsed(void *ptr);
void error_if_finished(char *file,DArray *tokens, size_t *index); __attribute__((warn_unused_result)) ArErr error_if_finished(char *file, DArray *tokens, size_t *index);
size_t skip_newlines_and_indents(DArray *tokens, size_t *index); size_t skip_newlines_and_indents(DArray *tokens, size_t *index);

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "return.h"
#include "../../lexer/token.h"
#include "../../memory.h"
#include "../literals/literals.h"
ParsedValueReturn parse_return(char *file, DArray *tokens, size_t *index) {
Token *token = darray_get(tokens, *index);
(*index)++;
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedReturn *parsedReturn = checked_malloc(sizeof(ParsedReturn));
parsedValue->type = AST_RETURN;
parsedValue->data = parsedReturn;
parsedReturn->line = token->line;
parsedReturn->column = token->column;
parsedReturn->length = token->length;
parsedReturn->value = parse_null();
if (*index >= tokens->size)
return (ParsedValueReturn){no_err, parsedValue};
token = darray_get(tokens, *index);
if (token->type == TOKEN_NEW_LINE)
return (ParsedValueReturn){no_err, parsedValue};
ParsedValueReturn value = parse_token(file, tokens, index, true);
if (value.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return value;
}
if (!value.value) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected value"),
NULL};
}
free_parsed(parsedReturn->value);
free(parsedReturn->value);
parsedReturn->value = value.value;
return (ParsedValueReturn){no_err, parsedValue};
}
void free_parsed_return(void *ptr) {
ParsedValue *parsedValue = ptr;
ParsedReturn *parsed_return = parsedValue->data;
free_parsed(parsed_return->value);
free(parsed_return->value);
free(parsed_return);
}

View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef RETURN_H
#define RETURN_H
#include "../parser.h"
typedef struct {
ParsedValue * value;
int64_t line;
int64_t column;
int64_t length;
} ParsedReturn;
ParsedValueReturn parse_return(char *file, DArray *tokens, size_t *index);
void free_parsed_return(void *ptr);
#endif // RETURN_H

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "string.h" #include "string.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
@@ -245,7 +251,7 @@ char *unquote(char *str, size_t *decoded_len) {
return unescaped; return unescaped;
} }
ParsedValue *parse_string(Token* token, bool to_unquote) { ParsedValueReturn parse_string(Token* token, bool to_unquote) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_STRING; parsedValue->type = AST_STRING;
ParsedString *parsedString = checked_malloc(sizeof(ParsedString)); ParsedString *parsedString = checked_malloc(sizeof(ParsedString));
@@ -253,11 +259,20 @@ ParsedValue *parse_string(Token* token, bool to_unquote) {
if (to_unquote) { if (to_unquote) {
parsedString->length = 0; parsedString->length = 0;
parsedString->string = unquote(token->value, &parsedString->length); parsedString->string = unquote(token->value, &parsedString->length);
if (!parsedString->string) {
free(parsedValue);
free(parsedString);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, NULL, "String Error",
"failed to unquote string %s", token->value),
NULL};
}
} else { } else {
parsedString->string = strdup(token->value); parsedString->string = checked_malloc(token->length);
memcpy(parsedString->string, token->value, token->length);
parsedString->length = token->length; parsedString->length = token->length;
} }
return parsedValue; return (ParsedValueReturn){no_err,parsedValue};
} }
void free_parsed_string(void *ptr) { void free_parsed_string(void *ptr) {

View File

@@ -1,3 +1,9 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef STRING_UTILS_H #ifndef STRING_UTILS_H
#define STRING_UTILS_H #define STRING_UTILS_H
@@ -15,7 +21,7 @@ char *swap_quotes(char *input, char quote);
char *unquote(char *str, size_t *decoded_len); char *unquote(char *str, size_t *decoded_len);
ParsedValue *parse_string(Token* token, bool to_unquote); ParsedValueReturn parse_string(Token* token, bool to_unquote);
void free_parsed_string(void *ptr); void free_parsed_string(void *ptr);

101
src/parser/while/while.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "while.h"
#include "../../lexer/token.h"
#include "../../memory.h"
#include "../parser.h"
#include <stddef.h>
ParsedValueReturn parse_while(char *file, DArray *tokens, size_t *index) {
Token *token = darray_get(tokens, *index);
(*index)++;
// Parse ( condition )
token = darray_get(tokens, *index);
if (token->type != TOKEN_LPAREN) {
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected '(' after while"),
NULL};
}
(*index)++;
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
return (ParsedValueReturn){err, NULL};
}
skip_newlines_and_indents(tokens, index);
ParsedValueReturn condition = parse_token(file, tokens, index, true);
if (condition.err.exists) {
return condition;
} else if (!condition.value) {
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected condition"),
NULL};
}
skip_newlines_and_indents(tokens, index);
token = darray_get(tokens, *index);
if (token->type != TOKEN_RPAREN) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"missing closing ')' in condition"),
NULL};
}
(*index)++;
err = error_if_finished(file, tokens, index);
if (err.exists) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
return (ParsedValueReturn){err, NULL};
}
// Parse the body
ParsedValueReturn parsed_content = parse_token(file, tokens, index, false);
if (parsed_content.err.exists) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
return parsed_content;
}
if (!parsed_content.value) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
}
ParsedValue *Parsedvalue = checked_malloc(sizeof(ParsedValue));
Parsedvalue->type = AST_WHILE;
ParsedWhile *Parsed_while = checked_malloc(sizeof(ParsedWhile));
Parsedvalue->data = Parsed_while;
Parsed_while->condition = condition.value;
Parsed_while->content = parsed_content.value;
return (ParsedValueReturn){no_err, Parsedvalue};
}
void free_parsed_while(void *ptr) {
ParsedValue *parsedValue = ptr;
ParsedWhile *parsed_while = parsedValue->data;
free_parsed(parsed_while->condition);
free(parsed_while->condition);
free_parsed(parsed_while->content);
free(parsed_while->content);
free(parsed_while);
}

20
src/parser/while/while.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef PARSE_WHILE_H
#define PARSE_WHILE_H
#include "../parser.h"
typedef struct {
ParsedValue * condition;
ParsedValue *content;
} ParsedWhile;
ParsedValueReturn parse_while(char *file, DArray *tokens, size_t *index);
void free_parsed_while(void *ptr);
#endif // PARSE_WHILE_H

23
src/returnTypes.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef RETURN_TYPES_H
#define RETURN_TYPES_H
#include <stdint.h>
#include "arobject.h"
#include <stdio.h>
typedef struct ArErr {
char path[FILENAME_MAX];
char message[128];
char type[64];
int64_t line;
int64_t column;
int length;
bool exists;
} ArErr;
#endif // RETURN_TYPES_

View File

@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "assignment.h"
void runtime_assignment(Translated *translated, RuntimeState *state,
struct Stack *stack) {
int64_t length = pop_bytecode(translated, state);
int64_t offset = pop_bytecode(translated, state);
int64_t prehash = pop_bytecode(translated, state);
int64_t from_register = pop_byte(translated, state);
void *data = arena_get(&translated->constants, offset);
uint64_t hash = runtime_hash(data, length, prehash);
ArgonObject *key = new_string_object(data, length, prehash, hash);
for (Stack *current_stack = stack; current_stack;
current_stack = current_stack->prev) {
ArgonObject *exists = hashmap_lookup_GC(current_stack->scope, hash);
if (exists) {
hashmap_insert_GC(current_stack->scope, hash, key,
state->registers[from_register], 0);
return;
}
}
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register],
0);
}

View File

@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef runtime_assignment_H
#define runtime_assignment_H
#include "../runtime.h"
#include "../objects/string/string.h"
void runtime_assignment(Translated *translated, RuntimeState *state,
struct Stack *stack);
#endif // runtime_assignment_H

226
src/runtime/call/call.c Normal file
View File

@@ -0,0 +1,226 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "call.h"
#include "../../hash_data/hash_data.h"
#include "../objects/string/string.h"
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0602
#endif
#include <psapi.h>
#include <windows.h>
double get_memory_usage_mb() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize / (1024.0 * 1024.0); // in MB
}
return 0.0;
}
#elif defined(__APPLE__)
#include <mach/mach.h>
double get_memory_usage_mb() {
struct task_basic_info info;
mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size) ==
KERN_SUCCESS) {
return info.resident_size / (1024.0 * 1024.0); // in MB
}
return 0.0;
}
#elif defined(__linux__)
#include <stdlib.h>
#include <string.h>
double get_memory_usage_mb() {
FILE *fp = fopen("/proc/self/status", "r");
if (!fp)
return 0.0;
char line[256];
size_t memory_kb = 0;
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, "VmRSS:", 6) == 0) {
sscanf(line + 6, "%zu", &memory_kb);
break;
}
}
fclose(fp);
return memory_kb / 1024.0; // Convert KB to MB
}
#else
double get_memory_usage_mb() {
// Unsupported platform
return 0.0;
}
#endif
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
ArgonObject **argv, ArErr *err, RuntimeState *state) {
run_call(original_object, argc, argv, state, true, err);
return state->registers[0];
}
void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
RuntimeState *state, bool CStackFrame, ArErr *err) {
ArgonObject *object = original_object;
if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION &&
object->type != TYPE_METHOD) {
ArgonObject *call_method = get_builtin_field_for_class(
get_builtin_field(object, __class__), __call__, original_object);
if (call_method) {
object = call_method;
}
}
if (object->type == TYPE_METHOD) {
ArgonObject *binding_object = get_builtin_field(object, __binding__);
if (binding_object) {
ArgonObject **new_call_args =
ar_alloc(sizeof(ArgonObject *) * (argc + 1));
new_call_args[0] = binding_object;
if (argc > 0) {
memcpy(new_call_args + 1, argv, argc * sizeof(ArgonObject *));
}
argv = new_call_args;
argc++;
}
ArgonObject *function_object = get_builtin_field(object, __function__);
if (function_object)
object = function_object;
}
if (object->type == TYPE_FUNCTION) {
if (argc != object->value.argon_fn->number_of_parameters) {
ArgonObject *type_object_name = get_builtin_field_for_class(
get_builtin_field(object, __class__), __name__, original_object);
ArgonObject *object_name =
get_builtin_field_for_class(object, __name__, original_object);
*err = create_err(
state->source_location.line, state->source_location.column,
state->source_location.length, state->path, "Type Error",
"%.*s %.*s takes %" PRIu64 " argument(s) but %" PRIu64 " was given",
(int)type_object_name->value.as_str->length,
type_object_name->value.as_str->data,
(int)object_name->value.as_str->length,
object_name->value.as_str->data,
object->value.argon_fn->number_of_parameters, argc);
return;
}
Stack *scope = create_scope(object->value.argon_fn->stack, true);
for (size_t i = 0; i < argc; i++) {
struct string_struct key = object->value.argon_fn->parameters[i];
ArgonObject *value = argv[i];
uint64_t hash = siphash64_bytes(key.data, key.length, siphash_key);
hashmap_insert_GC(scope->scope, hash,
new_string_object(key.data, key.length, 0, hash), value,
0);
}
if (CStackFrame) {
ArgonObject * registers[MAX_REGISTERS]; // fixed on the stack for speed purposes
StackFrame new_stackFrame = {
{object->value.argon_fn->translated.registerCount,
object->value.argon_fn->translated.registerAssignment,
NULL,
{object->value.argon_fn->bytecode, sizeof(uint8_t),
object->value.argon_fn->bytecode_length,
object->value.argon_fn->bytecode_length, false},
object->value.argon_fn->translated.constants,
object->value.argon_fn->translated.path},
{registers,
0,
object->value.argon_fn->translated.path,
NULL,
state->currentStackFramePointer,
{},
{}},
scope,
*state->currentStackFramePointer,
(*state->currentStackFramePointer)->depth + 1};
for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
new_stackFrame.state.registers[i] = NULL;
}
runtime(new_stackFrame.translated, new_stackFrame.state,
new_stackFrame.stack, err);
state->registers[0] = new_stackFrame.state.registers[0];
} else {
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame)+object->value.argon_fn->translated.registerCount *
sizeof(ArgonObject *));
*currentStackFrame = (StackFrame){
{object->value.argon_fn->translated.registerCount,
object->value.argon_fn->translated.registerAssignment,
NULL,
{object->value.argon_fn->bytecode, sizeof(uint8_t),
object->value.argon_fn->bytecode_length,
object->value.argon_fn->bytecode_length, false},
object->value.argon_fn->translated.constants,
object->value.argon_fn->translated.path},
{(ArgonObject **)((char*)currentStackFrame+sizeof(StackFrame)),
0,
object->value.argon_fn->translated.path,
NULL,
state->currentStackFramePointer,
{},
{}},
scope,
*state->currentStackFramePointer,
(*state->currentStackFramePointer)->depth + 1};
for (size_t i = 0; i < (*currentStackFrame).translated.registerCount; i++) {
(*currentStackFrame).state.registers[i] = NULL;
}
*state->currentStackFramePointer = currentStackFrame;
if ((*state->currentStackFramePointer)->depth >= 10000) {
double logval =
log10((double)(*state->currentStackFramePointer)->depth);
if (floor(logval) == logval) {
double memoryUsage = get_memory_usage_mb();
fprintf(stderr,
"Warning: %s:%" PRIu64 ":%" PRIu64
" the call stack depth has exceeded %" PRIu64,
state->path, state->source_location.line,
state->source_location.column,
(*state->currentStackFramePointer)->depth);
if (memoryUsage) {
fprintf(stderr, ", memory usage at %f MB\n", memoryUsage);
} else {
fprintf(stderr, "\n");
}
}
};
return;
}
} else if (object->type == TYPE_NATIVE_FUNCTION) {
state->registers[0] = object->value.native_fn(argc, argv, err, state);
if (err->exists && strlen(err->path) == 0) {
err->line = state->source_location.line;
err->column = state->source_location.column;
err->length = state->source_location.length;
strcpy(err->path, state->path);
}
return;
}
ArgonObject *type_object_name = get_builtin_field_for_class(
get_builtin_field(original_object, __class__), __name__, original_object);
*err = create_err(state->source_location.line, state->source_location.column,
state->source_location.length, state->path, "Type Error",
"'%.*s' object is not callable",
(int)type_object_name->value.as_str->length,
type_object_name->value.as_str->data);
}

17
src/runtime/call/call.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef runtime_call_H
#define runtime_call_H
#include "../runtime.h"
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
ArgonObject **argv, ArErr *err, RuntimeState *state);
void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
RuntimeState *state, bool CStackFrame, ArErr *err);
#endif // runtime_call_H

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "declaration.h"
void runtime_declaration(Translated *translated, RuntimeState *state,
struct Stack *stack, ArErr *err) {
int64_t length = pop_bytecode(translated, state);
int64_t offset = pop_bytecode(translated, state);
int64_t prehash = pop_bytecode(translated, state);
int64_t from_register = pop_byte(translated, state);
void *data = arena_get(&translated->constants, offset);
uint64_t hash = runtime_hash(data, length, prehash);
ArgonObject *exists = hashmap_lookup_GC(stack->scope, hash);
if (exists) {
*err = create_err(
state->source_location.line, state->source_location.column,
state->source_location.length, state->path, "Runtime Error",
"Identifier '%.*s' has already been declared in the current scope",
length, arena_get(&translated->constants, offset));
}
ArgonObject *key = new_string_object(data, length, prehash, hash);
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register],
0);
}

View File

@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef runtime_declaration_H
#define runtime_declaration_H
#include "../runtime.h"
#include "../objects/string/string.h"
void runtime_declaration(Translated *translated, RuntimeState *state,
struct Stack *stack, ArErr *err);
#endif // runtime_declaration_H

View File

@@ -1,16 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "darray_armem.h" #include "darray_armem.h"
#include "../../../memory.h" #include "../../../memory.h"
#include <gc/gc.h> #include <gc.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
void darray_armem_init(darray_armem *arr, size_t element_size) { void darray_armem_init(darray_armem *arr, size_t element_size) {
if (element_size > CHUNK_SIZE) {
fprintf(stderr, "darray_armem_init: element size larger than chunk size\n");
exit(EXIT_FAILURE);
}
arr->element_size = element_size; arr->element_size = element_size;
arr->size = 0; arr->size = 0;
arr->capacity = CHUNK_SIZE; arr->capacity = CHUNK_SIZE / element_size;
arr->data = ar_alloc(CHUNK_SIZE * element_size); arr->data = ar_alloc(CHUNK_SIZE); // fixed-size byte allocation
arr->resizable = true; arr->resizable = true;
if (!arr->data) { if (!arr->data) {
fprintf(stderr, "darray_armem_init: allocation failed\n"); fprintf(stderr, "darray_armem_init: allocation failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -22,15 +34,21 @@ void darray_armem_resize(darray_armem *arr, size_t new_size) {
fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n"); fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
size_t new_capacity = ((new_size + CHUNK_SIZE) / CHUNK_SIZE) * CHUNK_SIZE;
size_t required_bytes = new_size * arr->element_size;
size_t new_capacity_bytes =required_bytes*2;
size_t new_capacity = new_capacity_bytes / arr->element_size;
if (!new_capacity) {
return;
}
if (new_capacity != arr->capacity) { if (new_capacity != arr->capacity) {
void *new_data = ar_alloc(new_capacity * arr->element_size); arr->data = ar_realloc(arr->data, new_capacity_bytes);
memccpy(new_data,arr->data, arr->element_size, arr->capacity); if (!arr->data) {
if (!new_data) {
fprintf(stderr, "darray_armem_resize: reallocation failed\n"); fprintf(stderr, "darray_armem_resize: reallocation failed\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
arr->data = new_data;
arr->capacity = new_capacity; arr->capacity = new_capacity;
} }
@@ -61,11 +79,11 @@ void darray_armem_pop(darray_armem *arr, void (*free_data)(void *)) {
return; return;
if (free_data) { if (free_data) {
void *target = (char *)arr->data + (arr->size-1) * arr->element_size; void *target = (char *)arr->data + (arr->size - 1) * arr->element_size;
free_data(target); free_data(target);
} }
darray_armem_resize(arr, arr->size-1); darray_armem_resize(arr, arr->size - 1);
} }
void *darray_armem_get(darray_armem *arr, size_t index) { void *darray_armem_get(darray_armem *arr, size_t index) {
@@ -104,7 +122,6 @@ void darray_armem_free(darray_armem *arr, void (*free_data)(void *)) {
free_data(element); free_data(element);
} }
} }
free(arr->data);
arr->data = NULL; arr->data = NULL;
arr->size = 0; arr->size = 0;
arr->capacity = 0; arr->capacity = 0;

View File

@@ -1,10 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef darray_armem_H #ifndef darray_armem_H
#define darray_armem_H #define darray_armem_H
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#define CHUNK_SIZE 1048576 #define CHUNK_SIZE 4096
typedef struct { typedef struct {
void *data; void *data;

View File

@@ -1,25 +1,90 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "hashmap.h" #include "hashmap.h"
#include "../../../memory.h" #include "../../../memory.h"
#include <gc/gc.h> #include <gc.h>
#include <inttypes.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct hashmap_GC *createHashmap_GC() { struct hashmap_GC *createHashmap_GC() {
size_t size = 8; struct hashmap_GC *t =
struct hashmap_GC *t = (struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC)); (struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
t->size = size; t->size = 0;
t->order = 1; t->order = 1;
t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size); t->list = NULL;
memset(t->list, 0, sizeof(struct node_GC *) * size); t->hashmap_count = 0;
t->count = 0;
t->inline_count = 0;
return t; return t;
} }
static int compare_node_asc(const void *a, const void *b) {
const struct node_GC *na = *(const struct node_GC **)a;
const struct node_GC *nb = *(const struct node_GC **)b;
// Ascending order (smallest order first)
if (na->order < nb->order)
return -1;
if (na->order > nb->order)
return 1;
return 0;
}
struct node_GC ** hashmap_GC_to_array(struct hashmap_GC *t,
size_t *array_length) {
size_t array_size = 8;
*array_length = 0;
struct node_GC ** array = ar_alloc(array_size * sizeof(struct node_GC*));
for (size_t i = 0; i < t->inline_count; i++) {
if (*array_length >= array_size) {
array_size *= 2;
array = ar_realloc(array, array_size * sizeof(struct node_GC*));
}
array[(*array_length)++] = &t->inline_values[i];
}
for (size_t i = 0; i < t->size; i++) {
struct node_GC *list = t->list[i];
struct node_GC *temp = list;
while (temp) {
if (*array_length >= array_size) {
array_size *= 2;
array = ar_realloc(array, array_size * sizeof(struct node_GC*));
}
array[(*array_length)++] = temp;
temp = temp->next;
}
}
qsort(array, *array_length, sizeof(struct node_GC*), compare_node_asc);
return array;
}
void clear_hashmap_GC(struct hashmap_GC *t) {
if (!t->count)
return;
t->order = 1;
t->count = 0;
t->inline_count = 0;
t->hashmap_count = 0;
memset(t->list, 0, sizeof(struct node_GC *) * t->size);
}
void resize_hashmap_GC(struct hashmap_GC *t) { void resize_hashmap_GC(struct hashmap_GC *t) {
int old_size = t->size; int old_size = t->size;
int new_size = old_size * 2; int new_size = old_size * 2;
if (new_size == 0)
new_size = 8;
struct node_GC **old_list = t->list; struct node_GC **old_list = t->list;
@@ -28,22 +93,36 @@ void resize_hashmap_GC(struct hashmap_GC *t) {
memset(t->list, 0, sizeof(struct node_GC *) * new_size); memset(t->list, 0, sizeof(struct node_GC *) * new_size);
t->size = new_size; t->size = new_size;
t->count = 0; if (!old_list)
return;
t->hashmap_count = 0;
// Rehash old entries into new list // Rehash old entries into new list
for (int i = 0; i < old_size; i++) { for (int i = 0; i < old_size; i++) {
struct node_GC *temp = old_list[i]; struct node_GC *temp = old_list[i];
while (temp) { while (temp) {
hashmap_insert_GC(t, temp->hash, temp->key, temp->val, hashmap_insert_GC(t, temp->hash, temp->key, temp->val,
temp->order); // Will increment count temp->order); // Will increment count
temp = temp->next; temp = temp->next;
} }
} }
} }
int hashCode_GC(struct hashmap_GC *t, uint64_t hash) { return hash % t->size; } int hashCode_GC(struct hashmap_GC *t, uint64_t hash) {
return hash & (t->size - 1);
}
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) { int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
for (size_t i = 0; i < t->inline_count; i++) {
if (t->inline_values[i].hash == hash) {
size_t length = t->inline_count - i;
if (length > 1) {
memmove(&t->inline_values[i], &t->inline_values[i + 1],
(length - 1) * sizeof(struct node_GC));
}
t->inline_count--;
return 1;
}
}
int pos = hashCode_GC(t, hash); int pos = hashCode_GC(t, hash);
struct node_GC *list = t->list[pos]; struct node_GC *list = t->list[pos];
struct node_GC *temp = list; struct node_GC *temp = list;
@@ -59,18 +138,30 @@ int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
prev = temp; prev = temp;
temp = temp->next; temp = temp->next;
} }
list = NULL;
prev = NULL;
temp = NULL;
return 0; return 0;
} }
void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key, void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
void *val, size_t order) { void *val, size_t order) {
if (!order) { if (!order) {
order = t->order++; order = t->order++;
} }
if ((t->count + 1) > t->size * 0.75) { for (size_t i = 0; i < t->inline_count; i++) {
if (t->inline_values[i].hash == hash) {
t->inline_values[i].val = val;
return;
}
}
if (!t->list && t->inline_count < INLINE_HASHMAP_ARRAY_SIZE) {
t->inline_values[t->inline_count].hash = hash;
t->inline_values[t->inline_count].key = key;
t->inline_values[t->inline_count].val = val;
t->inline_values[t->inline_count].order = order;
t->inline_count++;
t->count++;
return;
}
if ((t->hashmap_count + 1) > t->size * 0.75) {
resize_hashmap_GC(t); resize_hashmap_GC(t);
} }
@@ -95,10 +186,18 @@ void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
newNode->order = order; newNode->order = order;
newNode->next = list; newNode->next = list;
t->list[pos] = newNode; t->list[pos] = newNode;
t->hashmap_count++;
t->count++; t->count++;
} }
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) { void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) {
size_t stop = t->inline_count;
for (size_t i = 0; i < stop; i++) {
if (t->inline_values[i].hash == hash)
return t->inline_values[i].val;
}
if (!t->list)
return NULL;
int pos = hashCode_GC(t, hash); int pos = hashCode_GC(t, hash);
struct node_GC *list = t->list[pos]; struct node_GC *list = t->list[pos];
struct node_GC *temp = list; struct node_GC *temp = list;

Some files were not shown because too many files have changed in this diff Show More