Compare commits

...

122 Commits

Author SHA1 Message Date
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
140 changed files with 5669 additions and 1726 deletions

View File

@@ -1,21 +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: with:
submodules: recursive 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'
@@ -24,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/*"

7
.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,5 @@ build
*.yy.c *.yy.c
*.yy.h *.yy.h
out.arbin
rand_test.ar
__arcache__ __arcache__
argon_modules

10
.gitmodules vendored
View File

@@ -1,6 +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"] [submodule "external/cwalk"]
path = external/cwalk path = external/cwalk
url = https://github.com/likle/cwalk.git 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": ["testing.ar"],
"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)
@@ -30,9 +34,10 @@ add_custom_command(
add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H}) add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H})
# Step 3: Add executable # Step 3: Add executable
add_executable(argon external/xxhash/xxhash.c external/cwalk/src/cwalk.c ${CFILES} ${LEXER_C}) add_executable(argon external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c external/linenoise/linenoise.c ${CFILES} ${LEXER_C})
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 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/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)
@@ -47,12 +52,12 @@ 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

View File

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

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,37 +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 external/cwalk/src/cwalk.c $(shell find src -name '*.c') LDFLAGS = -lgc -lgmp -lm
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function -Iexternal/cwalk/include
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) native: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -O3 -march=native -o $(BINARY) $(CFILES) $(CFLAGS) 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 -O0 -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,9 @@
<!--
SPDX-FileCopyrightText: 2025 William Bell
SPDX-License-Identifier: GPL-3.0-or-later
-->
# Chloride # Chloride
An Argon interpreter written in C An Argon interpreter written in C

4
app.py Normal file
View File

@@ -0,0 +1,4 @@
def f():
return f()
f()

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"
@@ -25,20 +30,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,3 +1,7 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
import struct import struct
from enum import Enum, EnumMeta, auto from enum import Enum, EnumMeta, auto

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,4 +1,6 @@
# SPDX-FileCopyrightText: 2025 William Bell
# SPDX-License-Identifier: GPL-3.0-or-later
let __makeFile(name, type, data) = do let __makeFile(name, type, data) = do
let File = {name: name, type: type, data: data} let File = {name: name, type: type, data: data}

View File

@@ -1,7 +1,10 @@
# SPDX-FileCopyrightText: 2025 William Bell
#
# SPDX-License-Identifier: GPL-3.0-or-later
import random import random
myfile = open("rand_test.ar","w") import sys
for i in range(10000000): for i in range(10000000):
myfile.write("\"") sys.stdout.write("\"hello world\"\n")
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"}]

83
src/arobject.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* 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 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_OBJECT,
} ArgonType;
typedef struct {
void *data;
size_t capacity;
size_t size;
struct hashmap *hashmap;
} ConstantArena;
typedef struct {
uint8_t registerCount;
DArray *return_jumps;
DArray bytecode;
ConstantArena constants;
char *path;
} Translated;
struct string_struct {
char *data;
size_t length;
};
typedef struct Stack {
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;
};
// full definition of ArgonObject (no typedef again!)
struct ArgonObject {
ArgonType type;
ArgonType child_type;
struct hashmap_GC *dict;
union {
mpq_t *as_number;
struct string_struct as_str;
native_fn native_fn;
struct argon_function_struct argon_fn;
} value;
};
#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;

196
src/err.c Normal file
View File

@@ -0,0 +1,196 @@
/*
* 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 <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.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){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;
err.path = path;
err.line = line;
err.column = column;
err.length = length;
// Copy error type safely
strncpy(err.type, type, sizeof(err.type) - 1);
err.type[sizeof(err.type) - 1] = '\0';
// 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 (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");
}
}
}

13
src/err.h Normal file
View File

@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#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);

View File

@@ -1,21 +1,41 @@
/*
* 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;

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"

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 {

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
@@ -91,7 +97,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 +113,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
@@ -72,10 +78,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,15 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "arobject.h"
#include "dynamic_array/darray.h" #include "dynamic_array/darray.h"
#include "hashmap/hashmap.h"
#include "lexer/lexer.h" #include "lexer/lexer.h"
#include "lexer/token.h" #include "lexer/token.h"
#include "memory.h" #include "memory.h"
#include "parser/parser.h" #include "parser/parser.h"
#include "returnTypes.h"
#include "shell.h"
#include "runtime/runtime.h" #include "runtime/runtime.h"
#include "translator/translator.h" #include "translator/translator.h"
#include "../external/xxhash/xxhash.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>
@@ -20,11 +28,13 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#ifdef _WIN32 #ifdef _WIN32
#include <direct.h> #include <direct.h> // for _mkdir
#define mkdir(path, mode) _mkdir(path) #include <sys/stat.h> // for _stat
#include <windows.h>
#else #else
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#endif #endif
#include "../external/cwalk/include/cwalk.h" #include "../external/cwalk/include/cwalk.h"
#include <string.h> #include <string.h>
@@ -35,6 +45,33 @@
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#endif #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>
#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
char *get_current_directory() { char *get_current_directory() {
char *buffer = NULL; char *buffer = NULL;
@@ -65,27 +102,108 @@ char *get_current_directory() {
} }
int ensure_dir_exists(const char *path) { int ensure_dir_exists(const char *path) {
struct stat st = {0}; #ifdef _WIN32
struct _stat st;
if (stat(path, &st) == -1) { 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 // Directory does not exist, create it
if (mkdir(path, 0755) != 0) { if (mkdir(path, 0755) != 0) {
perror("mkdir failed"); perror("mkdir failed");
return -1; return -1;
} }
} else if (!S_ISDIR(st.st_mode)) {
fprintf(stderr, "Path exists but is not a directory\n");
return -1;
} }
#endif
return 0; return 0;
} }
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;
}
}
const char CACHE_FOLDER[] = "__arcache__"; const char CACHE_FOLDER[] = "__arcache__";
const char FILE_IDENTIFIER[5] = "ARBI"; const char FILE_IDENTIFIER[5] = "ARBI";
const char BYTECODE_EXTENTION[] = "arbin"; const char BYTECODE_EXTENTION[] = "arbin";
const uint32_t version_number = 0; const uint32_t version_number = 0;
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash) { int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash,
char *source_path) {
FILE *bytecode_file = fopen(joined_paths, "rb"); FILE *bytecode_file = fopen(joined_paths, "rb");
if (!bytecode_file) if (!bytecode_file) {
fprintf(stderr, "cache doesnt exist... compiling from source.\n");
return 1; 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}; char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
if (fread(&file_identifier_from_cache, 1, if (fread(&file_identifier_from_cache, 1,
sizeof(file_identifier_from_cache) - 1, sizeof(file_identifier_from_cache) - 1,
@@ -137,6 +255,8 @@ int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash) {
} }
bytecodeSize = le64toh(bytecodeSize); bytecodeSize = le64toh(bytecodeSize);
*translated_dest = init_translator(source_path);
arena_resize(&translated_dest->constants, constantsSize); arena_resize(&translated_dest->constants, constantsSize);
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) != if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
@@ -151,45 +271,55 @@ int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash) {
goto FAILED; goto FAILED;
} }
translated_dest->registerCount = register_count; fprintf(stderr, "cache exists and is valid, so will be used.\n");
fclose(bytecode_file); fclose(bytecode_file);
return 0; return 0;
FAILED: FAILED:
fprintf(stderr, "cache is invalid... compiling from source.\n");
fclose(bytecode_file); fclose(bytecode_file);
return 1; return 1;
} }
ArgonObject *execute(char*absolute_path) { Translated load_argon_file(char *path, ArErr *err) {
clock_t start, end; clock_t start, end;
clock_t beginning = clock();
double time_spent, total_time_spent = 0; double time_spent, total_time_spent = 0;
const char *basename_ptr; const char *basename_ptr;
size_t basename_length; size_t basename_length;
cwk_path_get_basename(absolute_path, &basename_ptr, &basename_length); cwk_path_get_basename(path, &basename_ptr, &basename_length);
if (!basename_ptr) return NULL; if (!basename_ptr) {
*err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'",
path);
return (Translated){};
}
char basename[FILENAME_MAX]; char basename[FILENAME_MAX];
memcpy(basename, basename_ptr, basename_length); memcpy(basename, basename_ptr, basename_length);
size_t parent_directory_length; size_t parent_directory_length;
cwk_path_get_dirname(absolute_path, &parent_directory_length); cwk_path_get_dirname(path, &parent_directory_length);
char parent_directory[FILENAME_MAX]; char parent_directory[FILENAME_MAX];
memcpy(parent_directory, absolute_path, parent_directory_length); memcpy(parent_directory, path, parent_directory_length);
parent_directory[parent_directory_length] = '\0'; parent_directory[parent_directory_length] = '\0';
char cache_folder_path[FILENAME_MAX]; char cache_folder_path[FILENAME_MAX];
cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path, sizeof(cache_folder_path)); cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path,
sizeof(cache_folder_path));
char cache_file_path[FILENAME_MAX]; char cache_file_path[FILENAME_MAX];
cwk_path_join(cache_folder_path, basename, cache_file_path, sizeof(cache_file_path)); cwk_path_join(cache_folder_path, basename, cache_file_path,
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION, cache_file_path, sizeof(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(absolute_path, "r"); FILE *file = fopen(path, "r");
if (!file) { if (!file) {
return NULL; *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_state_t *hash_state = XXH3_createState();
@@ -204,22 +334,23 @@ ArgonObject *execute(char*absolute_path) {
uint64_t hash = XXH3_64bits_digest(hash_state); uint64_t hash = XXH3_64bits_digest(hash_state);
XXH3_freeState(hash_state); XXH3_freeState(hash_state);
Translated translated = init_translator(); Translated translated;
if (load_cache(&translated, cache_file_path, hash) != 0) { if (load_cache(&translated, cache_file_path, hash, path) != 0) {
free_translator(&translated);
translated = init_translator();
DArray tokens; DArray tokens;
darray_init(&tokens, sizeof(Token)); darray_init(&tokens, sizeof(Token));
LexerState state = {absolute_path, file, 0, 0, &tokens}; LexerState state = {path, file, 0, 0, &tokens};
start = clock(); start = clock();
lexer(state); *err = lexer(state);
if (err->exists) {
darray_free(&tokens, free_token);
return (Translated){};
}
end = clock(); end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC; time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent; fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent);
printf("Lexer time taken: %f seconds\n", time_spent);
fclose(state.file); fclose(state.file);
DArray ast; DArray ast;
@@ -227,74 +358,132 @@ ArgonObject *execute(char*absolute_path) {
darray_init(&ast, sizeof(ParsedValue)); darray_init(&ast, sizeof(ParsedValue));
start = clock(); start = clock();
parser(absolute_path, &ast, &tokens, false); *err = parser(path, &ast, &tokens, false);
darray_free(&tokens, free_token);
if (err->exists) {
darray_free(&ast, free_parsed);
return (Translated){};
}
end = clock(); end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC; time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent; fprintf(stderr, "Parser time taken: %f seconds\n", time_spent);
printf("Parser time taken: %f seconds\n", time_spent);
darray_free(&tokens, free_token);
start = clock(); start = clock();
translate(&translated, &ast);
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(); end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC; time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent; fprintf(stderr, "Translation time taken: %f seconds\n", time_spent);
printf("Translation time taken: %f seconds\n", time_spent); #if defined(__linux__)
malloc_trim(0);
#endif
darray_free(&ast, free_parsed);
ensure_dir_exists(cache_folder_path); ensure_dir_exists(cache_folder_path);
file = fopen(cache_file_path, "wb"); file = fopen(cache_file_path, "wb");
uint64_t constantsSize = (uint64_t)translated.constants.size; uint64_t constantsSize = translated.constants.size;
uint64_t bytecodeSize = (uint64_t)translated.bytecode.size; uint64_t bytecodeSize = translated.bytecode.size;
uint32_t version_number_htole32ed = htole32(version_number); uint32_t version_number_htole32ed = htole32(version_number);
uint64_t net_hash = htole64(hash); uint64_t net_hash = htole64(hash);
constantsSize = htole64(constantsSize); constantsSize = htole64(constantsSize);
bytecodeSize = htole64(bytecodeSize); bytecodeSize = htole64(bytecodeSize);
fwrite(&FILE_IDENTIFIER, sizeof(char), strlen(FILE_IDENTIFIER), file); XXH64_state_t *hash_state = XXH64_createState();
fwrite(&version_number_htole32ed, sizeof(uint32_t), 1, file); XXH64_reset(hash_state, 0);
fwrite(&net_hash, sizeof(net_hash), 1, file);
fwrite(&translated.registerCount, sizeof(uint8_t), 1, file); write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char),
fwrite(&constantsSize, sizeof(uint64_t), 1, file); strlen(FILE_IDENTIFIER));
fwrite(&bytecodeSize, sizeof(uint64_t), 1, file); write_and_hash(file, hash_state, &version_number_htole32ed,
fwrite(translated.constants.data, 1, translated.constants.size, file); sizeof(uint32_t), 1);
fwrite(translated.bytecode.data, translated.bytecode.element_size, write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1);
translated.bytecode.size, file); 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); fclose(file);
} }
hashmap_free(translated.constants.hashmap, NULL);
start = clock(); Translated gc_translated = {
RuntimeState state = init_runtime_state(translated); translated.registerCount, NULL, {}, {}, translated.path};
ArgonObject *resp = runtime(translated,state); gc_translated.bytecode.data = ar_alloc(translated.bytecode.capacity);
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
end = clock(); translated.bytecode.capacity);
time_spent = (double)(end - start) / CLOCKS_PER_SEC; gc_translated.bytecode.element_size = translated.bytecode.element_size;
total_time_spent += time_spent; gc_translated.bytecode.size = translated.bytecode.size;
printf("Execution time taken: %f seconds\n", time_spent); gc_translated.bytecode.resizable = false;
printf("total time taken: %f seconds\n", total_time_spent); gc_translated.bytecode.capacity =
translated.bytecode.size * translated.bytecode.element_size;
free_translator(&translated); gc_translated.constants.data = ar_alloc(translated.constants.capacity);
return resp; 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;
darray_free(&translated.bytecode, NULL);
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;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
ar_memory_init(); ar_memory_init();
generate_siphash_key(siphash_key); generate_siphash_key(siphash_key);
init_types(); bootstrap_types();
char *CWD = get_current_directory(); bootstrap_globals();
if (argc <= 1) if (argc <= 1)
return -1; return shell();
char *CWD = get_current_directory();
char *path_non_absolute = argv[1]; char *path_non_absolute = argv[1];
char path[FILENAME_MAX]; char path[FILENAME_MAX];
cwk_path_get_absolute(CWD, path_non_absolute, path, cwk_path_get_absolute(CWD, path_non_absolute, path, sizeof(path));
sizeof(path));
free(CWD); free(CWD);
ArgonObject *resp = execute(path); ArErr err;
if (resp) return 0; Translated translated = load_argon_file(path, &err);
return -1; if (err.exists) {
output_err(err);
return 1;
}
clock_t start = clock(), end;
RuntimeState state = init_runtime_state(translated, path);
Stack *main_scope = create_scope(Global_Scope);
err = runtime(translated, state, main_scope);
end = clock();
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Execution time taken: %f seconds\n", time_spent);
if (runtime_hash_table)
hashmap_free(runtime_hash_table, NULL);
if (err.exists) {
output_err(err);
return 1;
}
// Your main thread code
return 0;
} }

View File

@@ -1,5 +1,11 @@
/*
* 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 <gmp.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)
@@ -27,14 +33,16 @@ void gmp_gc_free(void *ptr, size_t size) {
void ar_memory_init() { void ar_memory_init() {
GC_INIT(); GC_INIT();
mp_set_memory_functions(GC_malloc, gmp_gc_realloc, gmp_gc_free);
} }
void *ar_alloc(size_t size) { return GC_MALLOC(size); } void *ar_alloc(size_t size) { return GC_MALLOC(size); }
void *ar_realloc(void *old, size_t size) { return GC_REALLOC(old, size); }
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,3 +1,9 @@
/*
* 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
@@ -9,6 +15,7 @@
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);

View File

@@ -1,53 +1,102 @@
/*
* 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); Token *first_token = darray_get(tokens, *index);
(*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;
parsedValue->type = AST_ACCESS;
parsedValue->data = parsedAccess;
free(to_access); free(to_access);
darray_init(&parsedAccess->access, sizeof(ParsedValue)); darray_init(&parsedAccess->access, sizeof(ParsedValue));
if (first_token->type == TOKEN_DOT) { if (first_token->type == TOKEN_DOT) {
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);
ParsedValue *parsedString = parse_string(token, false); parsedAccess->line = token->line;
darray_push(&parsedAccess->access, parsedString); parsedAccess->column = token->column;
free(parsedString); parsedAccess->length = token->length;
ParsedValueReturn parsedString = parse_string(token, false);
if (parsedString.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return parsedString;
}
darray_push(&parsedAccess->access, parsedString.value);
free(parsedString.value);
parsedAccess->access_fields = true; parsedAccess->access_fields = true;
} else { } else {
parsedAccess->line = first_token->line;
parsedAccess->column = first_token->column;
parsedAccess->length = first_token->length;
parsedAccess->access_fields = false; parsedAccess->access_fields = false;
Token *token = first_token;
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);
ParsedValue *parsedValue = parse_token(file, tokens, index, true); if (err.exists) {
darray_push(&parsedAccess->access, parsedValue); free_parsed(parsedValue);
free(parsedValue); free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
ParsedValueReturn parsedAccessValue =
parse_token(file, tokens, index, true);
if (parsedAccessValue.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return parsedAccessValue;
} else if (!parsedAccessValue.value) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected value"),
NULL};
}
darray_push(&parsedAccess->access, parsedAccessValue.value);
free(parsedAccessValue.value);
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);
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_RBRACKET) { if (token->type == TOKEN_RBRACKET) {
break; break;
} else if (token->type != TOKEN_COLON) { } else if (token->type != TOKEN_COLON) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, free_parsed(parsedValue);
token->line, token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected colon"),
NULL};
} }
(*index)++; (*index)++;
} }
} }
parsedValue->type = AST_ACCESS;
parsedValue->data = parsedAccess;
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_access(void *ptr) { void free_parse_access(void *ptr) {

View File

@@ -1,3 +1,9 @@
/*
* 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"
@@ -7,10 +13,14 @@ typedef struct {
ParsedValue to_access; ParsedValue to_access;
bool access_fields; bool access_fields;
DArray access; DArray 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,3 +1,9 @@
/*
* 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"
@@ -7,8 +13,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.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);
switch (assign_to->type) { switch (assign_to->type) {
case AST_IDENTIFIER: case AST_IDENTIFIER:
@@ -18,36 +24,56 @@ ParsedValue *parse_assign(char *file, DArray *tokens, ParsedValue *assign_to,
ParsedCall *call = assign_to->data; ParsedCall *call = assign_to->data;
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) { if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) {
fprintf(stderr, free_parsed(assign_to);
"%s:%zu:%zu error: parameter names need to start with a letter " free(assign_to);
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);
} }
} }
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};
} }
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 = token->type;
(*index)++;
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; (*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);
ParsedValueReturn from = parse_token(file, tokens, index, true);
if (from.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return from;
}
assign->from = from.value;
if (!assign->from) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
}
return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_assign(void *ptr) { void free_parse_assign(void *ptr) {
@@ -55,7 +81,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

@@ -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"

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"
@@ -6,18 +12,22 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct operation {};
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));
} }
@@ -27,7 +37,10 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
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 last_position = 0;
size_t to_operate_on_last_position = 0; size_t to_operate_on_last_position = 0;
@@ -37,31 +50,32 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
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, 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); 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, 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 +88,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

@@ -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"
@@ -14,6 +20,7 @@
#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 "return/return.h"
#include "string/string.h" #include "string/string.h"
#include <gmp.h> #include <gmp.h>
#include <stdbool.h> #include <stdbool.h>
@@ -23,17 +30,18 @@
#include <string.h> #include <string.h>
const char *ValueTypeNames[] = { const char *ValueTypeNames[] = {
"string", "assign", "identifier", "number", "if statement", "string", "assign", "identifier", "number",
"access", "call", "declaration", "null", "boolean", "if statement", "access", "call", "declaration",
"do wrap", "operations", "list", "dictionary", "function"}; "null", "boolean", "do wrap", "operations",
"list", "dictionary", "function", "return"};
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 +62,20 @@ 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_RETURN:
return parse_return(file, tokens, index);
case TOKEN_LET:
return parse_declaration(file, tokens, index);
default: default:
break; break;
}; };
@@ -71,15 +83,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 +99,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);
@@ -120,14 +132,18 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
output = parse_dictionary(file, tokens, index); output = parse_dictionary(file, tokens, index);
break; 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:
@@ -138,18 +154,18 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
case TOKEN_ASSIGN_PLUS: case TOKEN_ASSIGN_PLUS:
case TOKEN_ASSIGN_SLASH: case TOKEN_ASSIGN_SLASH:
case TOKEN_ASSIGN_STAR: case TOKEN_ASSIGN_STAR:
output = parse_assign(file, tokens, output, index); output = parse_assign(file, tokens, output.value, 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:
case TOKEN_LBRACKET: case TOKEN_LBRACKET:
output = parse_access(file, tokens, index, output); output = parse_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 +177,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", "expected new line");
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 +216,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:
@@ -235,5 +257,9 @@ 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;
} }
} }

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;
@@ -40,27 +48,33 @@ typedef enum {
AST_OPERATION, AST_OPERATION,
AST_LIST, AST_LIST,
AST_DICTIONARY, AST_DICTIONARY,
AST_FUNCTION AST_FUNCTION,
AST_RETURN
} 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);

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"
#define ERR_MSG_MAX_LEN 256
typedef struct ArErr {
bool exists;
char *path;
int64_t line;
int64_t column;
int length;
char type[32];
char message[ERR_MSG_MAX_LEN];
} ArErr;
#endif // RETURN_TYPES_

View File

@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "access.h"
#include <stdio.h>
ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 3) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__get_attr__ expects 3 arguments, got %" PRIu64);
return ARGON_NULL;
}
ArgonObject *to_access = argv[0];
ArgonObject *access = argv[1];
bool check_field = argv[2] == ARGON_TRUE;
if (check_field) {
ArgonObject *value = get_field_l(to_access, access->value.as_str.data,
access->value.as_str.length, true, false);
if (value)
return value;
}
ArgonObject *name = get_field_for_class(
get_field(to_access, "__class__", false, false), "__name__", to_access);
*err = create_err(0, 0, 0, "", "Runtime Error",
"'%.*s' object has no attribute '%.*s'",
(int)name->value.as_str.length, name->value.as_str.data,
(int)access->value.as_str.length, access->value.as_str.data);
return ARGON_NULL;
}

View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef runtime_access_H
#define runtime_access_H
#include "../objects/literals/literals.h"
#include "../objects/object.h"
#include "../runtime.h"
#include <inttypes.h>
ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state);
#endif // runtime_access_H

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

@@ -0,0 +1,203 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0602
#endif
#include <windows.h>
#include <psapi.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) {
*err = run_call(original_object, argc, argv, state, true);
return state->registers[0];
}
ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
RuntimeState *state, bool CStackFrame) {
ArgonObject *object = original_object;
if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION &&
object->type != TYPE_METHOD) {
ArgonObject *call_method =
get_field_for_class(get_field(object, "__class__", false, false),
"__call__", original_object);
if (call_method) {
object = call_method;
}
}
if (object->type == TYPE_METHOD) {
ArgonObject *binding_object =
get_field(object, "__binding__", false, false);
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_field(object, "__function__", false, false);
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_field_for_class(get_field(object, "__class__", false, false),
"__name__", original_object);
ArgonObject *object_name =
get_field_for_class(object, "__name__", original_object);
return 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);
}
Stack *scope = create_scope(object->value.argon_fn.stack);
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), value, 0);
}
StackFrame new_stackFrame = {
{object->value.argon_fn.translated.registerCount,
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},
{state->registers,
0,
object->value.argon_fn.translated.path,
NULL,
state->currentStackFramePointer,
{},
{}},
scope,
*state->currentStackFramePointer,
(*state->currentStackFramePointer)->depth + 1};
if (CStackFrame) {
return runtime(new_stackFrame.translated, new_stackFrame.state, new_stackFrame.stack);
} else {
if (((*state->currentStackFramePointer)->depth + 1) % STACKFRAME_CHUNKS ==
0) {
*state->currentStackFramePointer =
ar_alloc(sizeof(StackFrame) * STACKFRAME_CHUNKS);
} else {
*state->currentStackFramePointer = *state->currentStackFramePointer + 1;
}
**state->currentStackFramePointer = new_stackFrame;
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 no_err;
}
} else if (object->type == TYPE_NATIVE_FUNCTION) {
ArErr err = no_err;
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;
err.path = state->path;
}
return err;
}
ArgonObject *type_object_name =
get_field_for_class(get_field(original_object, "__class__", false, false),
"__name__", original_object);
return 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);
ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
RuntimeState *state, bool CStackFrame);
#endif // runtime_call_H

View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "declaration.h"
ArErr runtime_declaration(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);
uint64_t hash = runtime_hash(arena_get(&translated->constants, offset), length, prehash);
ArgonObject * exists = hashmap_lookup_GC(stack->scope, hash);
if (exists) {
return 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(arena_get(&translated->constants, offset), length);
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register], 0);
return no_err;
}

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"
ArErr runtime_declaration(Translated *translated, RuntimeState *state,
struct Stack *stack);
#endif // runtime_declaration_H

View File

@@ -1,3 +1,9 @@
/*
* 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/gc.h>
@@ -6,11 +12,17 @@
#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,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"
@@ -9,7 +15,8 @@
struct hashmap_GC *createHashmap_GC() { struct hashmap_GC *createHashmap_GC() {
size_t size = 8; size_t size = 8;
struct hashmap_GC *t = (struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC)); struct hashmap_GC *t =
(struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
t->size = size; t->size = size;
t->order = 1; t->order = 1;
t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size); t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size);
@@ -35,13 +42,15 @@ void resize_hashmap_GC(struct hashmap_GC *t) {
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) {
int pos = hashCode_GC(t, hash); int pos = hashCode_GC(t, hash);
@@ -66,7 +75,7 @@ int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
} }
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++;
} }

View File

@@ -1,10 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef HASHMAP_GC_H #ifndef HASHMAP_GC_H
#define HASHMAP_GC_H #define HASHMAP_GC_H
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
typedef struct ArgonObject ArgonObject;
struct node_GC { struct node_GC {
uint64_t hash; uint64_t hash;
void *key; void *key;

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 <stdio.h> #include <stdio.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 LINKEDLIST_H #ifndef LINKEDLIST_H
#define LINKEDLIST_H #define LINKEDLIST_H

View File

@@ -1,5 +1,12 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "../../runtime.h" #include "../../runtime.h"
#include "../object.h" #include "../object.h"
#include "../string/string.h"
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -7,34 +14,37 @@
ArgonObject *ARGON_FUNCTION_TYPE = NULL; ArgonObject *ARGON_FUNCTION_TYPE = NULL;
void init_function_type() { ArgonObject *create_argon_native_function(char*name, native_fn native_fn) {
ARGON_FUNCTION_TYPE = init_argon_class("Function"); ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_FUNCTION_TYPE);
object->type = TYPE_NATIVE_FUNCTION;
add_field(object, "__name__", new_string_object(name, strlen(name)));
object->value.native_fn = native_fn;
return object;
} }
void load_argon_function(Translated *translated, RuntimeState *state, void load_argon_function(Translated *translated, RuntimeState *state,
struct Stack stack) { struct Stack *stack) {
ArgonObject *object = init_child_argon_object(ARGON_FUNCTION_TYPE); ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_FUNCTION_TYPE);
object->type = TYPE_FUNCTION; object->type = TYPE_FUNCTION;
uint64_t offset = pop_bytecode(translated, state); uint64_t offset = pop_bytecode(translated, state);
uint64_t length = pop_bytecode(translated, state); uint64_t length = pop_bytecode(translated, state);
object->name = ar_alloc_atomic(length + 1); add_field(object, "__name__", new_string_object(arena_get(&translated->constants, offset), length));
memcpy(object->name, arena_get(&translated->constants, offset), length); object->value.argon_fn.translated = *translated;
object->name[length] = '\0';
object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state); object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state);
object->value.argon_fn.parameters = object->value.argon_fn.parameters =
ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(char *)); ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(struct string_struct));
for (size_t i = 0; i < object->value.argon_fn.number_of_parameters; i++) { for (size_t i = 0; i < object->value.argon_fn.number_of_parameters; i++) {
offset = pop_bytecode(translated, state); offset = pop_bytecode(translated, state);
length = pop_bytecode(translated, state); length = pop_bytecode(translated, state);
object->value.argon_fn.parameters[i] = ar_alloc_atomic(length + 1); object->value.argon_fn.parameters[i].data = arena_get(&translated->constants, offset);
memcpy(object->value.argon_fn.parameters[i], arena_get(&translated->constants, offset), length); object->value.argon_fn.parameters[i].length = length;
object->value.argon_fn.parameters[i][length] = '\0';
} }
offset = pop_bytecode(translated, state); offset = pop_bytecode(translated, state);
length = pop_bytecode(translated, state); length = pop_bytecode(translated, state);
darray_armem_init(&object->value.argon_fn.bytecode, sizeof(uint64_t)); object->value.argon_fn.bytecode = arena_get(&translated->constants, offset);
darray_armem_resize(&object->value.argon_fn.bytecode, length/object->value.argon_fn.bytecode.element_size); object->value.argon_fn.bytecode_length = length;
memcpy(object->value.argon_fn.bytecode.data, arena_get(&translated->constants, offset), length);
object->value.argon_fn.stack = stack; object->value.argon_fn.stack = stack;
state->registers[0]=object; state->registers[0]=object;
} }

View File

@@ -1,9 +1,17 @@
/*
* 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 "../object.h" #include "../object.h"
void init_function_type(); extern ArgonObject *ARGON_FUNCTION_TYPE;
ArgonObject *load_argon_function(Translated *translated, RuntimeState *state, struct Stack stack); ArgonObject *create_argon_native_function(char*name, native_fn native_fn);
ArgonObject *load_argon_function(Translated *translated, RuntimeState *state, struct Stack *stack);
#endif // FUNCTION_H #endif // FUNCTION_H

View File

@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "../object.h"
#include <string.h>
#include "literals.h"
ArgonObject *ARGON_NULL_TYPE = NULL;
ArgonObject *ARGON_NULL = NULL;
ArgonObject *ARGON_BOOL_TYPE = NULL;
ArgonObject *ARGON_TRUE = NULL;
ArgonObject *ARGON_FALSE = NULL;

View File

@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef RUNTIME_LITERALS_H
#define RUNTIME_LITERALS_H
#include "../object.h"
extern ArgonObject *ARGON_NULL_TYPE;
extern ArgonObject *ARGON_NULL;
extern ArgonObject *ARGON_BOOL_TYPE;
extern ArgonObject *ARGON_FALSE;
extern ArgonObject *ARGON_TRUE;
void init_literals();
#endif // RUNTIME_LITERALS_H

View File

@@ -1,14 +0,0 @@
#include "../../internals/hashmap/hashmap.h"
#include "../object.h"
#include <string.h>
#include "null.h"
ArgonObject *ARGON_NULL_TYPE = NULL;
ArgonObject *ARGON_NULL = NULL;
void init_null() {
ARGON_NULL_TYPE = init_argon_class("NULL_TYPE");
ARGON_NULL = init_child_argon_object(ARGON_NULL_TYPE);
ARGON_NULL->type=TYPE_NULL;
}

View File

@@ -1,10 +0,0 @@
#ifndef NULL_H
#define NULL_H
#include "../object.h"
extern ArgonObject *ARGON_NULL;
void init_null();
#endif // NULL_H

View File

@@ -0,0 +1,402 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "number.h"
#include "../functions/functions.h"
#include "../string/string.h"
#include <gmp.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
ArgonObject *ARGON_NUMBER_TYPE;
#include "../../call/call.h"
#include "../literals/literals.h"
#include <gmp.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* change SIGNIFICANT_DIGITS to taste (15 mimics double-ish behaviour) */
#define SIGNIFICANT_DIGITS 15
ArgonObject *ARGON_NUMBER_TYPE___new__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__new__ expects 2 arguments, got %" PRIu64, argc);
return ARGON_NULL;
}
ArgonObject *self = argv[0];
ArgonObject *object = argv[1];
self->type = TYPE_STRING;
ArgonObject *boolean_convert_method = get_field_for_class(
get_field(object, "__class__", false, false), "__number__", object);
if (boolean_convert_method) {
ArgonObject *boolean_object =
argon_call(boolean_convert_method, 0, NULL, err, state);
if (err->exists)
return ARGON_NULL;
return boolean_object;
}
ArgonObject *type_name = get_field_for_class(
get_field(object, "__class__", false, false), "__name__", object);
*err = create_err(
0, 0, 0, "", "Runtime Error", "cannot convert type '%.*s' to number",
type_name->value.as_str.length, type_name->value.as_str.data);
return ARGON_NULL;
}
ArgonObject *ARGON_NUMBER_TYPE___number__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 1) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__number__ expects 1 arguments, got %" PRIu64, argc);
return ARGON_NULL;
}
return argv[0];
}
ArgonObject *ARGON_NUMBER_TYPE___boolean__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 1) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
return ARGON_NULL;
}
return mpq_cmp_si(*argv[0]->value.as_number, 0, 1) == 0 ? ARGON_FALSE
: ARGON_TRUE;
}
ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__add__ expects 2 arguments, got %" PRIu64, argc);
return ARGON_NULL;
}
if (argv[1]->type != TYPE_NUMBER) {
ArgonObject *type_name = get_field_for_class(
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
*err = create_err(0, 0, 0, "", "Runtime Error",
"__add__ cannot perform addition between a number and %.*s",
type_name->value.as_str.length,
type_name->value.as_str.data);
return ARGON_NULL;
}
mpq_t r;
mpq_init(r);
mpq_add(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
ArgonObject *result = new_number_object(r);
mpq_clear(r);
return result;
}
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__subtract__ expects 2 arguments, got %" PRIu64, argc);
return ARGON_NULL;
}
mpq_t r;
mpq_init(r);
if (argv[1]->type != TYPE_NUMBER) {
ArgonObject *type_name = get_field_for_class(
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
*err = create_err(0, 0, 0, "", "Runtime Error",
"__subtract__ cannot perform subtraction between number and %.*s",
type_name->value.as_str.length,
type_name->value.as_str.data);
return ARGON_NULL;
}
mpq_sub(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
ArgonObject *result = new_number_object(r);
mpq_clear(r);
return result;
}
ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 1) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__string__ expects 1 arguments, got %" PRIu64, argc);
return NULL;
}
mpq_t *num = argv[0]->value.as_number;
/* If denominator == 1, print numerator as full integer */
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
char *num_str =
mpz_get_str(NULL, 10, mpq_numref(*num)); /* malloc'd by GMP */
ArgonObject *result = new_string_object_null_terminated(num_str);
free(num_str);
return result;
}
/* Not an integer: use mpf to format with SIGNIFICANT_DIGITS precision */
mpf_t f;
mpf_init(f);
mpf_set_q(f, *num); /* set mpf from mpq */
mp_exp_t exp; /* exponent returned by mpf_get_str */
/* Request SIGNIFICANT_DIGITS significant digits. If you want "max accurate",
* pass 0. */
char *mant = mpf_get_str(NULL, &exp, 10, SIGNIFICANT_DIGITS, f);
/* For zero, mpf_get_str returns an empty string and exp == 0 per GMP docs. */
if (mant == NULL) {
mpf_clear(f);
return new_string_object_null_terminated("0");
}
/* handle zero specially */
if (mant[0] == '\0' || (mant[0] == '0' && mant[1] == '\0')) {
free(mant);
mpf_clear(f);
return new_string_object_null_terminated("0");
}
/* mant may include a leading '-' according to some docs; detect sign */
int negative = 0;
char *digits = mant;
if (mant[0] == '-') {
negative = 1;
digits = mant + 1;
}
size_t L = strlen(digits); /* number of digit characters returned */
/* mpf_get_str represents value as 0.digits * 10^exp (i.e. assumed decimal
* point after the leading zero) */
/* For scientific-format exponent (1.d..eE) we use scientific_exponent = exp -
* 1 */
long scientific_exp = (long)exp - 1L;
/* Decide whether to use fixed or scientific, mimic C's %g rule:
use scientific if exponent < -4 or exponent >= SIGNIFICANT_DIGITS */
int use_scientific =
(scientific_exp < -4) || (scientific_exp >= SIGNIFICANT_DIGITS);
/* Build output into dynamic buffer */
/* Worst-case: sign + 1 digit + '.' + (SIGNIFICANT_DIGITS-1) digits + 'e' +
* sign + exponent digits + NUL */
size_t buf_size = (size_t)(negative ? 1 : 0) + 1 + 1 +
(SIGNIFICANT_DIGITS - 1) + 1 + 1 + 32 + 1;
/* For fixed form we may need more if exp > L (we append zeros). Allocate a
* bit extra. */
if (!use_scientific) {
/* maximum integer digits = max(exp, L) but exp could be large; be
* conservative */
buf_size += (size_t)((exp > (mp_exp_t)L) ? (size_t)exp : L) + 16;
}
char *out = malloc(buf_size);
if (!out) {
free(mant);
mpf_clear(f);
*err = create_err(0, 0, 0, "", "Runtime Error", "out of memory");
return NULL;
}
char *p = out;
if (negative) {
*p++ = '-';
}
if (use_scientific) {
/* scientific: d.dddddeE where d = digits[0], fractional = digits[1..L-1]
*/
*p++ = digits[0];
if (L > 1) {
*p++ = '.';
memcpy(p, digits + 1, L - 1);
p += L - 1;
}
/* append exponent */
int written = snprintf(p, buf_size - (p - out), "e%+ld", scientific_exp);
if (written < 0)
written = 0;
p += written;
} else {
/* fixed form: move decimal point right by 'exp' places in 0.digits * 10^exp
*/
/* integer part length = exp (may be <=0 meaning 0) */
long int_len = (long)exp;
if (int_len <= 0) {
/* 0.xxx... form */
*p++ = '0';
*p++ = '.';
/* need (-int_len) leading zeros after decimal */
for (long i = 0; i < -int_len; ++i)
*p++ = '0';
/* then digits */
memcpy(p, digits, L);
p += L;
} else {
/* integer part uses first int_len digits of digits (if available), else
* digits plus zeros */
if ((size_t)int_len <= L) {
/* put first int_len digits as integer part */
memcpy(p, digits, (size_t)int_len);
p += int_len;
/* fractional part exists if L > int_len */
if (L > (size_t)int_len) {
*p++ = '.';
memcpy(p, digits + int_len, L - int_len);
p += L - int_len;
}
} else {
/* digits provide only part of integer, append zeros */
memcpy(p, digits, L);
p += L;
for (long i = 0; i < int_len - (long)L; ++i)
*p++ = '0';
/* no fractional part */
}
}
}
*p = '\0';
/* Clean up */
free(mant);
mpf_clear(f);
ArgonObject *result = new_string_object_null_terminated(out);
free(out);
return result;
}
void create_ARGON_NUMBER_TYPE() {
ARGON_NUMBER_TYPE = new_object();
add_field(ARGON_NUMBER_TYPE, "__name__",
new_string_object_null_terminated("number"));
add_field(
ARGON_NUMBER_TYPE, "__string__",
create_argon_native_function("__string__", ARGON_NUMBER_TYPE___string__));
add_field(ARGON_NUMBER_TYPE, "__new__",
create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__));
add_field(
ARGON_NUMBER_TYPE, "__number__",
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
add_field(ARGON_NUMBER_TYPE, "__boolean__",
create_argon_native_function("__boolean__",
ARGON_NUMBER_TYPE___boolean__));
add_field(ARGON_NUMBER_TYPE, "__add__",
create_argon_native_function("__add__",
ARGON_NUMBER_TYPE___add__));
add_field(ARGON_NUMBER_TYPE, "__subtract__",
create_argon_native_function("__subtract__",
ARGON_NUMBER_TYPE___subtract__));
}
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
z->_mp_alloc = limbs_count;
z->_mp_size = 0;
z->_mp_d = ar_alloc(limbs_count * sizeof(mp_limb_t));
}
void mpq_init_gc_managed(mpq_t q, size_t num_limbs, size_t den_limbs) {
mpz_init_gc_managed(mpq_numref(q), num_limbs);
mpz_init_gc_managed(mpq_denref(q), den_limbs);
mpq_set_ui(q, 0, 1); // initialize denominator to 1
}
void mpq_copy_to_gc(mpq_t dest, const mpq_t src) {
size_t num_limbs = (size_t)abs(mpq_numref(src)->_mp_size);
size_t den_limbs = (size_t)abs(mpq_denref(src)->_mp_size);
dest->_mp_num._mp_size = mpq_numref(src)->_mp_size;
memcpy(dest->_mp_num._mp_d, mpq_numref(src)->_mp_d,
num_limbs * sizeof(mp_limb_t));
dest->_mp_den._mp_size = mpq_denref(src)->_mp_size;
memcpy(dest->_mp_den._mp_d, mpq_denref(src)->_mp_d,
den_limbs * sizeof(mp_limb_t));
}
mpq_t *mpq_new_gc_from(const mpq_t src) {
mpq_t *dest = ar_alloc(sizeof(mpq_t));
size_t num_limbs = (size_t)mpq_numref(src)->_mp_alloc;
size_t den_limbs = (size_t)mpq_denref(src)->_mp_alloc;
mpq_init_gc_managed(*dest, num_limbs, den_limbs);
mpq_copy_to_gc(*dest, src);
return dest;
}
ArgonObject *new_number_object(mpq_t number) {
ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE);
object->type = TYPE_NUMBER;
object->value.as_number = mpq_new_gc_from(number);
return object;
}
ArgonObject *new_number_object_from_long(long n, unsigned long d) {
ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE);
mpq_t r;
mpq_init(r);
mpq_set_si(r, n, d);
object->type = TYPE_NUMBER;
object->value.as_number = mpq_new_gc_from(r);
mpq_clear(r);
return object;
}
ArgonObject *new_number_object_from_double(double d) {
ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE);
mpq_t r;
mpq_init(r);
mpq_set_d(r, d);
object->type = TYPE_NUMBER;
object->value.as_number = mpq_new_gc_from(r);
mpq_clear(r);
return object;
}
void load_number(Translated *translated, RuntimeState *state) {
uint8_t to_register = pop_byte(translated, state);
size_t num_size = pop_bytecode(translated, state);
size_t num_pos = pop_bytecode(translated, state);
mpq_t r;
mpq_init(r);
mpz_t num;
mpz_init(num);
mpz_import(num, num_size, 1, 1, 0, 0,
arena_get(&translated->constants, num_pos));
mpq_set_num(r, num);
mpz_clear(num);
bool is_int = pop_byte(translated, state);
if (!is_int) {
size_t den_size = pop_bytecode(translated, state);
size_t den_pos = pop_bytecode(translated, state);
mpz_t den;
mpz_init(den);
mpz_import(den, den_size, 1, 1, 0, 0,
arena_get(&translated->constants, den_pos));
mpq_set_den(r, den);
mpz_clear(den);
} else {
mpz_set_si(mpq_denref(r), 1);
}
state->registers[to_register] = new_number_object(r);
mpq_clear(r);
}

View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef RUNTIME_NUMBER_H
#define RUNTIME_NUMBER_H
#include "../object.h"
extern ArgonObject *ARGON_NUMBER_TYPE;
void create_ARGON_NUMBER_TYPE();
ArgonObject *new_number_object(mpq_t number);
void load_number(Translated *translated, RuntimeState *state);
ArgonObject *new_number_object_from_double(double d);
ArgonObject *new_number_object_from_long(long n, unsigned long d);
#endif // RUNTIME_NUMBER_H

View File

@@ -1,37 +1,91 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "object.h" #include "object.h"
#include "../../hash_data/hash_data.h" #include "../../hash_data/hash_data.h"
#include "../../memory.h" #include "../../memory.h"
#include "type/type.h" #include "type/type.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h> #include <string.h>
ArgonObject *BASE_CLASS = NULL; ArgonObject *BASE_CLASS = NULL;
void init_base_field() { ArgonObject *new_object() {
// add_field(BASE_CLASS, "test", BASE_CLASS);
}
ArgonObject *init_child_argon_object(ArgonObject *cls) {
ArgonObject *object = init_argon_class(NULL);
object->self = object;
object->baseObject = cls;
add_field(object, "__call__", NULL);
return object;
}
ArgonObject *init_argon_class(char *name) {
ArgonObject *object = ar_alloc(sizeof(ArgonObject)); ArgonObject *object = ar_alloc(sizeof(ArgonObject));
object->name = name;
object->type = TYPE_OBJECT; object->type = TYPE_OBJECT;
object->self = NULL; object->dict = createHashmap_GC();
object->baseObject = ARGON_TYPE; add_field(object, "__class__", ARGON_TYPE_TYPE);
object->fields = createHashmap_GC(); add_field(object, "__base__", BASE_CLASS);
memset(&object->value, 0, sizeof(object->value));
return object; return object;
} }
void add_field(ArgonObject *target, char *name, ArgonObject *object) { void add_field(ArgonObject *target, char *name, ArgonObject *object) {
hashmap_insert_GC(target->fields, hashmap_insert_GC(target->dict,
siphash64_bytes(name, strlen(name), siphash_key), name, siphash64_bytes(name, strlen(name), siphash_key), name,
object, 0); object, 0);
} }
ArgonObject *bind_object_to_function(ArgonObject *object,
ArgonObject *function) {
ArgonObject *bound_method_wrapper = new_object();
bound_method_wrapper->type = TYPE_METHOD;
add_field(bound_method_wrapper, "__class__", ARGON_METHOD_TYPE);
add_field(bound_method_wrapper, "__binding__", object);
add_field(bound_method_wrapper, "__function__", function);
ArgonObject *function_name = get_field(function, "__name__", false, false);
if (function_name)
add_field(bound_method_wrapper, "__name__", function_name);
return bound_method_wrapper;
}
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
size_t length, ArgonObject *binding_object) {
char *field = "__base__";
size_t field_size = strlen(field);
while (target) {
ArgonObject *object = get_field_l(target, name, length, false, false);
if (object) {
if ((object->type == TYPE_FUNCTION ||
object->type == TYPE_NATIVE_FUNCTION) &&
binding_object) {
object = bind_object_to_function(binding_object, object);
}
return object;
}
target = get_field_l(target, field, field_size, false, false);
}
return NULL;
}
ArgonObject *get_field_l(ArgonObject *target, char *name, size_t length,
bool recursive, bool disable_method_wrapper) {
if(!target|| !target->dict) return NULL;
char *field = "__class__";
size_t field_size = strlen(field);
ArgonObject *object = hashmap_lookup_GC(
target->dict, siphash64_bytes(name, length, siphash_key));
if (!recursive || object)
return object;
ArgonObject *binding = target;
if (disable_method_wrapper)
binding = NULL;
return get_field_for_class_l(
hashmap_lookup_GC(target->dict,
siphash64_bytes(field, field_size, siphash_key)),
name, length, binding);
}
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive,
bool disable_method_wrapper) {
return get_field_l(target, name, strlen(name), recursive,
disable_method_wrapper);
}
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
ArgonObject *binding_object) {
return get_field_for_class_l(target, name, strlen(name), binding_object);
}

View File

@@ -1,53 +1,35 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef OBJECT_H #ifndef OBJECT_H
#define OBJECT_H #define OBJECT_H
#include "../internals/hashmap/hashmap.h" #include "../internals/hashmap/hashmap.h"
#include "../internals/dynamic_array_armem/darray_armem.h"
#include <gmp.h>
#include <stdbool.h>
#include "../runtime.h" #include "../runtime.h"
#include <stdbool.h>
extern ArgonObject *BASE_CLASS; extern ArgonObject *BASE_CLASS;
struct string_struct {
char *data;
size_t length;
};
struct argon_function_struct {
darray_armem bytecode;
struct Stack stack;
size_t number_of_parameters;
char** parameters;
};
typedef enum {
TYPE_NULL,
TYPE_BOOL,
TYPE_NUMBER,
TYPE_STRING,
TYPE_FUNCTION,
TYPE_NATIVE_FUNCTION,
TYPE_OBJECT, // generic user object
} ArgonType;
struct ArgonObject {
ArgonType type;
char* name;
ArgonObject *self;
ArgonObject *baseObject;
struct hashmap_GC *fields; // dynamic fields/methods
union {
mpq_t as_number;
bool as_bool;
struct string_struct as_str;
void *native_fn;
struct argon_function_struct argon_fn;
// others as needed
} value;
};
typedef struct ArgonObject ArgonObject; typedef struct ArgonObject ArgonObject;
void init_base_field(); ArgonObject *new_object();
ArgonObject* init_child_argon_object(ArgonObject *cls);
ArgonObject* init_argon_class(char*name); void add_field(ArgonObject *target, char *name, ArgonObject *object);
ArgonObject *bind_object_to_function(ArgonObject *object,
ArgonObject *function);
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
size_t length, ArgonObject *binding_object);
ArgonObject *get_field_l(ArgonObject *target, char *name, size_t length,
bool recursive, bool disable_method_wrapper);
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
ArgonObject *binding_object);
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive,
bool disable_method_wrapper);
void add_field(ArgonObject*target, char* name, ArgonObject *object);
#endif // OBJECT_H #endif // OBJECT_H

View File

@@ -1,20 +1,30 @@
/*
* SPDX-FileCopyrightText: 2025 William Bell
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "../object.h" #include "../object.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "string.h" #include "string.h"
#include "../number/number.h"
ArgonObject *ARGON_STRING_TYPE = NULL; ArgonObject *ARGON_STRING_TYPE = NULL;
void init_string_type() { ArgonObject *new_string_object(char*data, size_t length) {
ARGON_STRING_TYPE = init_argon_class("String"); ArgonObject * object = new_object();
add_field(object, "__class__", ARGON_STRING_TYPE);
} add_field(object, "length", new_number_object_from_long(length, 1));
ArgonObject *init_string_object(char*data, size_t length) {
ArgonObject * object = init_child_argon_object(ARGON_STRING_TYPE);
object->type = TYPE_STRING; object->type = TYPE_STRING;
object->value.as_str.data = data; object->value.as_str.data = ar_alloc_atomic(length);
memcpy(object->value.as_str.data, data, length);
object->value.as_str.length = length; object->value.as_str.length = length;
return object; return object;
} }
ArgonObject *new_string_object_null_terminated(char*data) {
return new_string_object(data, strlen(data));
}

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