Compare commits
113 Commits
prerelease
...
prerelease
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9b1d23f79 | ||
|
|
6d3e79b731 | ||
|
|
b3ee64d294 | ||
|
|
e6ec0fa38a | ||
|
|
c8394228b3 | ||
| 70ba81bebc | |||
|
|
50ff9fbefc | ||
|
|
042c278b8d | ||
|
|
81efaaac07 | ||
| 3b0ec79955 | |||
|
|
4be8e8e32f | ||
|
|
5846adf025 | ||
|
|
daa8056b7a | ||
|
|
1a5abd9543 | ||
|
|
774890de1d | ||
|
|
fc7cfc7cfb | ||
|
|
d46a6dc209 | ||
|
|
23c4a7ebd1 | ||
|
|
57728af0b6 | ||
|
|
df040adf45 | ||
|
|
c2e0cdc6d6 | ||
|
|
571efe46b7 | ||
|
|
67569bffc2 | ||
|
|
f5ee0f6fc8 | ||
|
|
fd5b237dfe | ||
|
|
322716af0c | ||
|
|
c67b37d8b2 | ||
|
|
b9c0503d54 | ||
|
|
19268f3070 | ||
|
|
4f91bf48f3 | ||
|
|
4fc28d3b76 | ||
| c01dee80b0 | |||
| 0f0a3f5d31 | |||
|
|
f598c215e7 | ||
|
|
fff4f6bcb5 | ||
|
|
c322d5680f | ||
|
|
db650d8ccf | ||
|
|
6ad0b2c02e | ||
|
|
624a54c90c | ||
|
|
c856e7d654 | ||
|
|
a96023ced1 | ||
|
|
1908d9bbbb | ||
|
|
47db2ca27d | ||
|
|
2e7b3b4baa | ||
|
|
24163e3389 | ||
|
|
0c0832d131 | ||
|
|
1742a0c52d | ||
|
|
224039ba43 | ||
|
|
5e7ce495e4 | ||
|
|
35a0f35cf8 | ||
|
|
f9490ceac0 | ||
|
|
4cda311008 | ||
|
|
b3aa653076 | ||
|
|
fc3321bcf0 | ||
|
|
868b3bfc3d | ||
|
|
f5e241aba0 | ||
|
|
8c3ee3fe05 | ||
|
|
eb285b6e8f | ||
|
|
78a1edd572 | ||
|
|
b905026010 | ||
|
|
677afd9433 | ||
|
|
757da3f973 | ||
|
|
5a86510c3b | ||
|
|
fb8b6a89ae | ||
|
|
6ddf9953e7 | ||
|
|
1609227a42 | ||
|
|
51f6a88ce8 | ||
|
|
f420273471 | ||
|
|
4b2a747338 | ||
|
|
5277814af0 | ||
|
|
8928ab2d99 | ||
|
|
d08b307c6e | ||
|
|
6474329afc | ||
|
|
c49e67c839 | ||
|
|
25cb96e473 | ||
|
|
f11890a8b3 | ||
|
|
59b1d222c2 | ||
|
|
2fba132016 | ||
|
|
bddc2cdc79 | ||
|
|
e1b80b42d9 | ||
|
|
dab86925b4 | ||
|
|
0f45052dce | ||
|
|
68f4207216 | ||
|
|
f9f8ca08c6 | ||
|
|
0666b02c13 | ||
|
|
1654507835 | ||
|
|
d054ece8e2 | ||
|
|
4937942d6e | ||
|
|
82ea92183f | ||
|
|
5fb15b476f | ||
|
|
d1a455dbbe | ||
|
|
a81640747d | ||
|
|
4a1ed23f96 | ||
|
|
eb36d02fcb | ||
|
|
7b3a1e1835 | ||
|
|
8e53579682 | ||
|
|
0d8f262185 | ||
|
|
fc6f41d89b | ||
|
|
6a7ce72eb7 | ||
|
|
f84e5429a5 | ||
|
|
f4c7294267 | ||
|
|
be4b04a286 | ||
|
|
9d11122e93 | ||
|
|
241e447da0 | ||
|
|
dd750ab164 | ||
|
|
922b129250 | ||
|
|
c2df9c0e83 | ||
|
|
923503493e | ||
|
|
686cb08f11 | ||
|
|
1cfb4acda6 | ||
|
|
436f30330b | ||
|
|
5381967ed6 | ||
|
|
6f84a4a485 |
304
.github/workflows/release.yml
vendored
304
.github/workflows/release.yml
vendored
@@ -1,133 +1,231 @@
|
|||||||
|
# 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:
|
||||||
strategy:
|
runs-on: ubuntu-latest # build both architectures
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Linux
|
- uses: actions/checkout@v3
|
||||||
- name: Install build tools (Linux)
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y flex bison
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
- name: Install build tools (macOS)
|
|
||||||
if: runner.os == 'macOS'
|
|
||||||
run: brew install flex bison
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
- name: Install build tools (Windows)
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: choco install winflexbison -y
|
|
||||||
shell: pwsh
|
|
||||||
- name: Checkout code
|
|
||||||
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'
|
||||||
|
|
||||||
- name: Install Conan (Linux/macOS)
|
- name: Install Conan
|
||||||
if: runner.os != 'Windows'
|
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install conan
|
pip install conan
|
||||||
shell: bash
|
conan profile detect
|
||||||
|
|
||||||
- name: Install Conan (Windows)
|
- name: Build
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install conan
|
|
||||||
shell: pwsh
|
|
||||||
|
|
||||||
- name: Configure Conan (Linux/macOS)
|
|
||||||
if: runner.os != 'Windows'
|
|
||||||
run: conan profile detect
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Configure Conan (Windows)
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: conan profile detect
|
|
||||||
shell: pwsh
|
|
||||||
|
|
||||||
- name: Install dependencies and build (Linux/macOS)
|
|
||||||
if: runner.os != 'Windows'
|
|
||||||
run: |
|
run: |
|
||||||
conan install . --build=missing
|
conan install . --build=missing
|
||||||
conan build .
|
conan build .
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Install dependencies and build (Windows)
|
- name: Package
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: |
|
|
||||||
conan install . --build=missing
|
|
||||||
conan build .
|
|
||||||
shell: pwsh
|
|
||||||
|
|
||||||
- name: Determine if prerelease (Linux/macOS)
|
|
||||||
if: runner.os != 'Windows'
|
|
||||||
id: prerelease_check_unix
|
|
||||||
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
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Determine if prerelease (Windows)
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
id: prerelease_check_win
|
|
||||||
run: |
|
|
||||||
$TAG = $env:GITHUB_REF -replace 'refs/tags/', ''
|
|
||||||
if ($TAG -like 'prerelease-*') {
|
|
||||||
echo "true" > prerelease.txt
|
|
||||||
} else {
|
|
||||||
echo "false" > prerelease.txt
|
|
||||||
}
|
|
||||||
echo "prerelease=$(Get-Content prerelease.txt)" >> $env:GITHUB_OUTPUT
|
|
||||||
shell: pwsh
|
|
||||||
|
|
||||||
- name: Archive build folder (Linux/macOS)
|
|
||||||
if: runner.os != 'Windows'
|
|
||||||
run: |
|
run: |
|
||||||
TAG=${GITHUB_REF##refs/tags/}
|
TAG=${GITHUB_REF##refs/tags/}
|
||||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
FOLDER_NAME="chloride-$TAG-$OS-$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
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Archive build folder (Windows)
|
- name: Upload artifact
|
||||||
if: runner.os == 'Windows'
|
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: |
|
run: |
|
||||||
$TAG = $env:GITHUB_REF -replace 'refs/tags/', ''
|
python -m pip install --upgrade pip
|
||||||
$ARCH = if ([Environment]::Is64BitOperatingSystem) { 'x64' } else { 'x86' }
|
pip install conan
|
||||||
$FOLDER_NAME = "chloride-$TAG-windows-$ARCH"
|
conan profile detect
|
||||||
$TAR_NAME = "$FOLDER_NAME.zip"
|
|
||||||
Rename-Item build\bin $FOLDER_NAME
|
- name: Build
|
||||||
Copy-Item LICENSE $FOLDER_NAME
|
run: |
|
||||||
Compress-Archive -Path $FOLDER_NAME -DestinationPath $TAR_NAME
|
conan install . --build=missing
|
||||||
echo "TAR_NAME=$TAR_NAME" >> $env:GITHUB_ENV
|
conan build .
|
||||||
shell: pwsh
|
|
||||||
|
- 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
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
@@ -136,5 +234,5 @@ jobs:
|
|||||||
name: Release ${{ github.ref_name }}
|
name: Release ${{ github.ref_name }}
|
||||||
body: Automated release based on tag ${{ github.ref_name }}
|
body: Automated release based on tag ${{ github.ref_name }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: ${{ runner.os == 'Windows' && steps.prerelease_check_win.outputs.prerelease || steps.prerelease_check_unix.outputs.prerelease }}
|
prerelease: ${{ startsWith(github.ref_name, 'prerelease-') }}
|
||||||
artifacts: ${{ env.TAR_NAME }}
|
artifacts: "./artifacts/*"
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -64,5 +64,6 @@ build
|
|||||||
*.yy.c
|
*.yy.c
|
||||||
*.yy.h
|
*.yy.h
|
||||||
|
|
||||||
|
__isotope__
|
||||||
__arcache__
|
__arcache__
|
||||||
argon_modules
|
argon_modules
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -11,3 +11,6 @@
|
|||||||
[submodule "external/libdye"]
|
[submodule "external/libdye"]
|
||||||
path = external/libdye
|
path = external/libdye
|
||||||
url = https://github.com/Ugric/libdye.git
|
url = https://github.com/Ugric/libdye.git
|
||||||
|
[submodule "external/linenoise"]
|
||||||
|
path = external/linenoise
|
||||||
|
url = https://github.com/antirez/linenoise
|
||||||
|
|||||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -9,7 +9,7 @@
|
|||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/argon",
|
"program": "${workspaceFolder}/bin/argon",
|
||||||
"args": ["testing.ar"],
|
"args": [],
|
||||||
"stopAtEntry": true,
|
"stopAtEntry": true,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
|
|||||||
@@ -33,8 +33,16 @@ add_custom_command(
|
|||||||
# Step 2: Custom target for lexer
|
# Step 2: Custom target for lexer
|
||||||
add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H})
|
add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H})
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c ${CFILES} ${LEXER_C}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT WIN32)
|
||||||
|
list(APPEND SOURCES external/linenoise/linenoise.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Step 3: Add executable
|
# Step 3: Add executable
|
||||||
add_executable(argon external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c ${CFILES} ${LEXER_C})
|
add_executable(argon ${SOURCES})
|
||||||
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)
|
target_include_directories(argon PRIVATE ${CMAKE_SOURCE_DIR}/external/libdye/include)
|
||||||
@@ -52,12 +60,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
|
||||||
|
|||||||
23
Makefile
23
Makefile
@@ -2,26 +2,31 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# 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
|
||||||
|
|
||||||
CFILES = external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c $(shell find src -name '*.c')
|
|
||||||
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function -Werror=unused-result -Iexternal/cwalk/include -Iexternal/libdye/include
|
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function -Werror=unused-result -Iexternal/cwalk/include -Iexternal/libdye/include
|
||||||
BINARY = bin/argon
|
LDFLAGS = -lgc -lgmp -lm
|
||||||
|
|
||||||
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
|
||||||
@@ -29,13 +34,13 @@ debug: $(CFILES) $(LEXER_C) $(LEXER_H)
|
|||||||
|
|
||||||
full-debug: $(CFILES) $(LEXER_C) $(LEXER_H)
|
full-debug: $(CFILES) $(LEXER_C) $(LEXER_H)
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
gcc -g -O0 -fsanitize=address -fno-omit-frame-pointer -o $(BINARY) $(CFILES) $(CFLAGS)
|
gcc -g -O3 -fsanitize=address -fno-omit-frame-pointer -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
|
||||||
|
|
||||||
optimised: $(CFILES) $(LEXER_C) $(LEXER_H)
|
optimised: $(CFILES) $(LEXER_C) $(LEXER_H)
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS)
|
gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
|
||||||
${BINARY} rand_test.ar
|
${BINARY} rand_test.ar
|
||||||
gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS)
|
gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS) ${LDFLAGS}
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
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"
|
||||||
@@ -29,13 +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)
|
||||||
|
|
||||||
flex_path = which("flex")
|
flex_path = which("flex")
|
||||||
if not flex_path:
|
if not flex_path:
|
||||||
raise Exception("Flex not found in system PATH. Please install flex on your system.")
|
raise Exception("Flex not found in system PATH. Please install flex on Linux/macOS.")
|
||||||
|
|
||||||
tc.variables["FLEX_EXECUTABLE"] = flex_path
|
tc.variables["FLEX_EXECUTABLE"] = flex_path.replace("\\", "\\\\")
|
||||||
tc.generate()
|
tc.generate()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
|
|||||||
130
debug_arbin.py
130
debug_arbin.py
@@ -1,130 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import struct
|
|
||||||
from enum import Enum, EnumMeta, auto
|
|
||||||
|
|
||||||
class AutoEnumMeta(EnumMeta):
|
|
||||||
@classmethod
|
|
||||||
def __prepare__(metacls, clsname, bases, **kwargs):
|
|
||||||
d = super().__prepare__(clsname, bases, **kwargs)
|
|
||||||
d['_next_value'] = 254
|
|
||||||
return d
|
|
||||||
|
|
||||||
def _generate_next_value_(cls, name, start, count, last_values):
|
|
||||||
value = cls._next_value
|
|
||||||
cls._next_value += 1
|
|
||||||
return value
|
|
||||||
|
|
||||||
class OperationType(Enum, metaclass=AutoEnumMeta):
|
|
||||||
OP_LOAD_CONST = auto()
|
|
||||||
OP_DECLARE = auto()
|
|
||||||
OP_LOAD_NULL = auto()
|
|
||||||
OP_JUMP = auto()
|
|
||||||
|
|
||||||
class Types(Enum, metaclass=AutoEnumMeta):
|
|
||||||
TYPE_OP_STRING = auto()
|
|
||||||
TYPE_OP_NUMBER = auto()
|
|
||||||
|
|
||||||
def read_arbin(filename):
|
|
||||||
with open(filename, "rb") as f:
|
|
||||||
# Read and verify file identifier (4 bytes)
|
|
||||||
file_id = f.read(4)
|
|
||||||
if file_id != b"ARBI":
|
|
||||||
raise ValueError("Invalid file identifier")
|
|
||||||
|
|
||||||
# Read version number (uint64_t, little-endian)
|
|
||||||
version_number, = struct.unpack("<Q", f.read(8))
|
|
||||||
|
|
||||||
# Read regCount, constantsSize, bytecodeSize (all uint64_t, little-endian)
|
|
||||||
reg_count, = struct.unpack("<Q", f.read(8))
|
|
||||||
constants_size, = struct.unpack("<Q", f.read(8))
|
|
||||||
bytecode_size, = struct.unpack("<Q", f.read(8))
|
|
||||||
|
|
||||||
# Read constants buffer (raw bytes)
|
|
||||||
constants = f.read(constants_size)
|
|
||||||
|
|
||||||
# Read bytecode array (uint64_t, little-endian)
|
|
||||||
bytecode = []
|
|
||||||
for _ in range(bytecode_size):
|
|
||||||
instr, = struct.unpack("<Q", f.read(8))
|
|
||||||
bytecode.append(instr)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"version": version_number,
|
|
||||||
"register_count": reg_count,
|
|
||||||
"constants_size": constants_size,
|
|
||||||
"bytecode_size": bytecode_size,
|
|
||||||
"constants": constants,
|
|
||||||
"bytecode": bytecode,
|
|
||||||
}
|
|
||||||
|
|
||||||
class print_opcode:
|
|
||||||
def start(registers,data, i):
|
|
||||||
print()
|
|
||||||
match data['bytecode'][i]:
|
|
||||||
case OperationType.OP_LOAD_CONST.value:
|
|
||||||
return print_opcode.OP_LOAD_CONST(registers,data, i)
|
|
||||||
case OperationType.OP_DECLARE.value:
|
|
||||||
return print_opcode.OP_DECLARE(registers,data, i)
|
|
||||||
case OperationType.OP_LOAD_NULL.value:
|
|
||||||
return print_opcode.OP_LOAD_NULL(registers,data, i)
|
|
||||||
|
|
||||||
def OP_LOAD_CONST(registers,data, i) -> int:
|
|
||||||
print("OP_LOAD_CONST ", end="")
|
|
||||||
i+=1
|
|
||||||
register = data["bytecode"][i]
|
|
||||||
print("To Register",register,"", end="")
|
|
||||||
i+=1
|
|
||||||
match data["bytecode"][i]:
|
|
||||||
case Types.TYPE_OP_STRING.value:
|
|
||||||
print("TYPE_OP_STRING ", end="")
|
|
||||||
case Types.TYPE_OP_NUMBER.value:
|
|
||||||
print("TYPE_OP_NUMBER ", end="")
|
|
||||||
i+=1
|
|
||||||
length = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
offset = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
print("Length",length,"", end="")
|
|
||||||
print("Offset",offset,"")
|
|
||||||
registers[register] = data["constants"][offset:offset+length].decode()
|
|
||||||
print("const value:", registers[register])
|
|
||||||
return i
|
|
||||||
|
|
||||||
def OP_DECLARE(registers,data, i) -> int:
|
|
||||||
print("OP_DECLARE ", end="")
|
|
||||||
i+=1
|
|
||||||
length = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
offset = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
from_register = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
print("Name Length",length,"", end="")
|
|
||||||
print("Name Offset",offset,"", end="")
|
|
||||||
print("From Register",from_register,"")
|
|
||||||
print("output: let", data['constants'][offset:offset+length].decode(),'=',registers[from_register])
|
|
||||||
return i
|
|
||||||
def OP_LOAD_NULL(registers,data, i) -> int:
|
|
||||||
print("OP_LOAD_NULL ", end="")
|
|
||||||
i+=1
|
|
||||||
to_register = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
print("To Register",to_register,"")
|
|
||||||
registers[to_register] = "null"
|
|
||||||
return i
|
|
||||||
if __name__ == "__main__":
|
|
||||||
filename = "out.arbin"
|
|
||||||
data = read_arbin(filename)
|
|
||||||
print(f"Version: {data['version']}")
|
|
||||||
print(f"Register Count: {data['register_count']}")
|
|
||||||
print(f"Constants Size: {data['constants_size']} bytes")
|
|
||||||
print(f"Bytecode Length: {data['bytecode_size']} elements")
|
|
||||||
|
|
||||||
registers = ["null"]*data['register_count']
|
|
||||||
|
|
||||||
i=0
|
|
||||||
while i<len(data["bytecode"]):
|
|
||||||
i=print_opcode.start(registers,data,i)
|
|
||||||
1
external/linenoise
vendored
Submodule
1
external/linenoise
vendored
Submodule
Submodule external/linenoise added at d895173d67
@@ -1,56 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
let __makeFile(name, type, data) = do
|
|
||||||
let File = {name: name, type: type, data: data}
|
|
||||||
let save(path) = do
|
|
||||||
let file = file.write(path)
|
|
||||||
file.buffer(data)
|
|
||||||
file.close()
|
|
||||||
File.save = save
|
|
||||||
return File
|
|
||||||
|
|
||||||
let __multipart(req, res) = do
|
|
||||||
let boundary = buffer().from(req.headers["content-type"].splitN("boundary=", 2)[1])
|
|
||||||
let newLineSplit = buffer().from("\r\n\r\n")
|
|
||||||
let parts = req.buffer.body.split(boundary)
|
|
||||||
for (i from 0 to parts.length) do
|
|
||||||
let str = parts[i].to("string")
|
|
||||||
if (str == "" || str=="--" || str=="--\r\n") continue
|
|
||||||
str = null
|
|
||||||
let headers = {}
|
|
||||||
let lines = parts[i].splitN(newLineSplit, 2)
|
|
||||||
let headerLines = lines[0].to("string").split("\r\n")
|
|
||||||
for (j from 0 to headerLines.length) do
|
|
||||||
let header = headerLines[j].splitN(": ", 2)
|
|
||||||
if (header.length != 2) continue
|
|
||||||
headers[header[0].lower()] = header[1]
|
|
||||||
if (lines.length != 2) continue
|
|
||||||
let body = lines[1]
|
|
||||||
if (i != parts.length-1) do
|
|
||||||
body = body.slice(0, body.length-4)
|
|
||||||
if ("content-disposition" in headers) do
|
|
||||||
let disposition = headers["content-disposition"].split("; ")
|
|
||||||
if (disposition[0] == "form-data") do
|
|
||||||
let name = json.parse(disposition[1].splitN("=", 2)[1])
|
|
||||||
if (disposition.length >= 3) do
|
|
||||||
let filename = json.parse(disposition[2].splitN("=", 2)[1])
|
|
||||||
req.files[name] = __makeFile(filename, headers["content-type"], body)
|
|
||||||
else do
|
|
||||||
req.formdata[name] = body.to("string")
|
|
||||||
res.next()
|
|
||||||
|
|
||||||
|
|
||||||
let formdata(req, res) = do
|
|
||||||
req.formdata = {}
|
|
||||||
req.files = {}
|
|
||||||
|
|
||||||
if (req.method != "POST") return res.next()
|
|
||||||
if ("content-type" not in req.headers) return res.next()
|
|
||||||
let loweredContentType = req.headers["content-type"].lower()
|
|
||||||
if (loweredContentType.startswith("multipart/form-data")) return __multipart(req, res)
|
|
||||||
else if (loweredContentType.startswith("application/x-www-form-urlencoded")) req.formdata = url.decodeURLQuery(req.buffer.body.to("string"))
|
|
||||||
else if (loweredContentType.startswith("application/json")) req.formdata = json.parse(req.buffer.body.to("string"))
|
|
||||||
else req.files.file = __makeFile("file", req.headers["content-type"], req.buffer.body)
|
|
||||||
res.next()
|
|
||||||
10
gentest.py
10
gentest.py
@@ -1,10 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import random
|
|
||||||
import sys
|
|
||||||
|
|
||||||
for i in range(10000000):
|
|
||||||
sys.stdout.write("\"hello world\"\n")
|
|
||||||
|
|
||||||
2893
src/LICENSE_c.h
Normal file
2893
src/LICENSE_c.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,36 @@
|
|||||||
#include "runtime/internals/hashmap/hashmap.h"
|
#include "runtime/internals/hashmap/hashmap.h"
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
__base__,
|
||||||
|
__class__,
|
||||||
|
__name__,
|
||||||
|
__binding__,
|
||||||
|
__function__,
|
||||||
|
|
||||||
|
BUILT_IN_ARRAY_COUNT,
|
||||||
|
|
||||||
|
__add__,
|
||||||
|
__string__,
|
||||||
|
__subtract__,
|
||||||
|
__multiply__,
|
||||||
|
__divide__,
|
||||||
|
__new__,
|
||||||
|
__init__,
|
||||||
|
__boolean__,
|
||||||
|
__get_attr__,
|
||||||
|
field__address,
|
||||||
|
__call__,
|
||||||
|
__number__,
|
||||||
|
field_length,
|
||||||
|
__getattribute__,
|
||||||
|
__set_attr__,
|
||||||
|
__hash__,
|
||||||
|
__repr__,
|
||||||
|
|
||||||
|
BUILT_IN_FIELDS_COUNT,
|
||||||
|
} built_in_fields;
|
||||||
|
|
||||||
typedef struct ArErr ArErr;
|
typedef struct ArErr ArErr;
|
||||||
typedef struct RuntimeState RuntimeState;
|
typedef struct RuntimeState RuntimeState;
|
||||||
|
|
||||||
@@ -28,6 +58,7 @@ typedef enum ArgonType {
|
|||||||
TYPE_FUNCTION,
|
TYPE_FUNCTION,
|
||||||
TYPE_NATIVE_FUNCTION,
|
TYPE_NATIVE_FUNCTION,
|
||||||
TYPE_METHOD,
|
TYPE_METHOD,
|
||||||
|
TYPE_DICTIONARY,
|
||||||
TYPE_OBJECT,
|
TYPE_OBJECT,
|
||||||
} ArgonType;
|
} ArgonType;
|
||||||
|
|
||||||
@@ -40,6 +71,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t registerCount;
|
uint8_t registerCount;
|
||||||
|
uint8_t registerAssignment;
|
||||||
DArray *return_jumps;
|
DArray *return_jumps;
|
||||||
DArray bytecode;
|
DArray bytecode;
|
||||||
ConstantArena constants;
|
ConstantArena constants;
|
||||||
@@ -47,11 +79,15 @@ typedef struct {
|
|||||||
} Translated;
|
} Translated;
|
||||||
|
|
||||||
struct string_struct {
|
struct string_struct {
|
||||||
|
uint64_t prehash;
|
||||||
|
uint64_t hash;
|
||||||
char *data;
|
char *data;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
bool hash_computed;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Stack {
|
typedef struct Stack {
|
||||||
|
uint64_t fake_new_scopes;
|
||||||
struct hashmap_GC *scope;
|
struct hashmap_GC *scope;
|
||||||
struct Stack *prev;
|
struct Stack *prev;
|
||||||
} Stack;
|
} Stack;
|
||||||
@@ -67,17 +103,33 @@ struct argon_function_struct {
|
|||||||
uint64_t column;
|
uint64_t column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct built_in_slot {
|
||||||
|
built_in_fields field;
|
||||||
|
ArgonObject *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct as_number {
|
||||||
|
union {
|
||||||
|
mpq_t *mpq;
|
||||||
|
int64_t i64;
|
||||||
|
} n;
|
||||||
|
bool is_int64;
|
||||||
|
};
|
||||||
|
|
||||||
// full definition of ArgonObject (no typedef again!)
|
// full definition of ArgonObject (no typedef again!)
|
||||||
struct ArgonObject {
|
struct ArgonObject {
|
||||||
ArgonType type;
|
|
||||||
ArgonType child_type;
|
|
||||||
struct hashmap_GC *dict;
|
struct hashmap_GC *dict;
|
||||||
|
size_t built_in_slot_length;
|
||||||
|
struct built_in_slot built_in_slot[BUILT_IN_ARRAY_COUNT];
|
||||||
union {
|
union {
|
||||||
mpq_t *as_number;
|
struct as_number *as_number;
|
||||||
struct string_struct as_str;
|
struct hashmap_GC *as_hashmap;
|
||||||
|
struct string_struct *as_str;
|
||||||
native_fn native_fn;
|
native_fn native_fn;
|
||||||
struct argon_function_struct argon_fn;
|
struct argon_function_struct *argon_fn;
|
||||||
} value;
|
} value;
|
||||||
|
ArgonType type;
|
||||||
|
bool as_bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AROBJECT_H
|
#endif // AROBJECT_H
|
||||||
21
src/err.c
21
src/err.c
@@ -7,6 +7,7 @@
|
|||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "../external/libdye/include/dye.h"
|
#include "../external/libdye/include/dye.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
@@ -61,20 +61,23 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const ArErr no_err = (ArErr){false};
|
const ArErr no_err = (ArErr){"", "", "", 0, 0, 0, false};
|
||||||
|
|
||||||
ArErr create_err(int64_t line, int64_t column, int length, char *path,
|
ArErr create_err(int64_t line, int64_t column, int length, char *path,
|
||||||
const char *type, const char *fmt, ...) {
|
const char *type, const char *fmt, ...) {
|
||||||
ArErr err;
|
ArErr err;
|
||||||
err.exists = true;
|
err.exists = true;
|
||||||
err.path = path;
|
if (path)
|
||||||
|
strcpy(err.path, path);
|
||||||
|
else {
|
||||||
|
err.path[0] = '\0';
|
||||||
|
}
|
||||||
err.line = line;
|
err.line = line;
|
||||||
err.column = column;
|
err.column = column;
|
||||||
err.length = length;
|
err.length = length;
|
||||||
|
|
||||||
// Copy error type safely
|
// Copy error type safely
|
||||||
strncpy(err.type, type, sizeof(err.type) - 1);
|
snprintf(err.type, sizeof(err.type), "%s", (char *)type);
|
||||||
err.type[sizeof(err.type) - 1] = '\0';
|
|
||||||
|
|
||||||
// Format error message
|
// Format error message
|
||||||
va_list args;
|
va_list args;
|
||||||
@@ -104,7 +107,7 @@ void output_err(ArErr err) {
|
|||||||
dyefg(stderr, DYE_RESET);
|
dyefg(stderr, DYE_RESET);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
if (err.path && err.line) {
|
if (strlen(err.path) && err.line) {
|
||||||
dyefg(stderr, DYE_GRAY);
|
dyefg(stderr, DYE_GRAY);
|
||||||
fprintf(stderr, " --> ");
|
fprintf(stderr, " --> ");
|
||||||
dyefg(stderr, DYE_CYAN);
|
dyefg(stderr, DYE_CYAN);
|
||||||
@@ -112,7 +115,7 @@ void output_err(ArErr err) {
|
|||||||
dyefg(stderr, DYE_GRAY);
|
dyefg(stderr, DYE_GRAY);
|
||||||
fprintf(stderr, ":");
|
fprintf(stderr, ":");
|
||||||
dyefg(stderr, DYE_YELLOW);
|
dyefg(stderr, DYE_YELLOW);
|
||||||
fprintf(stderr, "%" PRIu64 , err.line);
|
fprintf(stderr, "%" PRIu64, err.line);
|
||||||
dyefg(stderr, DYE_GRAY);
|
dyefg(stderr, DYE_GRAY);
|
||||||
fprintf(stderr, ":");
|
fprintf(stderr, ":");
|
||||||
dyefg(stderr, DYE_YELLOW);
|
dyefg(stderr, DYE_YELLOW);
|
||||||
@@ -141,7 +144,7 @@ void output_err(ArErr err) {
|
|||||||
fprintf(stderr, " ");
|
fprintf(stderr, " ");
|
||||||
}
|
}
|
||||||
fprintf(stderr, "|\n");
|
fprintf(stderr, "|\n");
|
||||||
for (ssize_t i = 0;i<len;i++) {
|
for (ssize_t i = 0; i < len; i++) {
|
||||||
if (buffer[i] == '\n') {
|
if (buffer[i] == '\n') {
|
||||||
buffer[i] = '\0';
|
buffer[i] = '\0';
|
||||||
break;
|
break;
|
||||||
@@ -165,7 +168,7 @@ void output_err(ArErr err) {
|
|||||||
dyefg(stderr, DYE_RESET);
|
dyefg(stderr, DYE_RESET);
|
||||||
fprintf(stderr, "%.*s",
|
fprintf(stderr, "%.*s",
|
||||||
(int)len - (int)skipped_chars - (int)err.column -
|
(int)len - (int)skipped_chars - (int)err.column -
|
||||||
(int)err.length+1,
|
(int)err.length + 1,
|
||||||
line_starts + (int)err.column + err.length - 1);
|
line_starts + (int)err.column + err.length - 1);
|
||||||
for (int64_t i = 0; i < err.column - 1; i++) {
|
for (int64_t i = 0; i < err.column - 1; i++) {
|
||||||
fprintf(stderr, " ");
|
fprintf(stderr, " ");
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef RETURN_TYPE_H
|
||||||
|
#define RETURN_TYPE_H
|
||||||
#include "returnTypes.h"
|
#include "returnTypes.h"
|
||||||
|
|
||||||
extern const ArErr no_err;
|
extern const ArErr no_err;
|
||||||
@@ -11,3 +13,4 @@ extern const ArErr no_err;
|
|||||||
ArErr create_err(int64_t line, int64_t column, int length, char *path, const char *type,
|
ArErr create_err(int64_t line, int64_t column, int length, char *path, const char *type,
|
||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
void output_err(ArErr err);
|
void output_err(ArErr err);
|
||||||
|
#endif // RETURN_TYPE_H
|
||||||
@@ -40,9 +40,5 @@ uint64_t siphash64_bytes(const void *data, size_t len,const uint8_t hash_key[16]
|
|||||||
if (siphash(data, len, hash_key, out, sizeof(out)) != 0)
|
if (siphash(data, len, hash_key, out, sizeof(out)) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64_t hash = 0;
|
return *(uint64_t *)out;
|
||||||
for (int i = 0; i < 8; ++i)
|
|
||||||
hash |= ((uint64_t)out[i]) << (8 * i);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
469
src/import.c
Normal file
469
src/import.c
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
#include "../external/cwalk/include/cwalk.h"
|
||||||
|
#include "../external/xxhash/xxhash.h"
|
||||||
|
#include "arobject.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "hash_data/hash_data.h"
|
||||||
|
#include "hashmap/hashmap.h"
|
||||||
|
#include "lexer/lexer.h"
|
||||||
|
#include "lexer/token.h"
|
||||||
|
#include "runtime/internals/hashmap/hashmap.h"
|
||||||
|
#include "runtime/runtime.h"
|
||||||
|
#include "translator/translator.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h> // for _mkdir
|
||||||
|
#include <sys/stat.h> // for _stat
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include "err.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
// Windows / MinGW usually uses little-endian, so these can be no-ops
|
||||||
|
// But define them explicitly to avoid implicit declaration warnings
|
||||||
|
|
||||||
|
static inline uint32_t le32toh(uint32_t x) { return x; }
|
||||||
|
static inline uint64_t le64toh(uint64_t x) { return x; }
|
||||||
|
static inline uint32_t htole32(uint32_t x) { return x; }
|
||||||
|
static inline uint64_t htole64(uint64_t x) { return x; }
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <endian.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <libkern/OSByteOrder.h>
|
||||||
|
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||||
|
#define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||||
|
#define htole64(x) OSSwapHostToLittleInt64(x)
|
||||||
|
#define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||||
|
// Add others as needed
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/endian.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ensure_dir_exists(const char *path) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
struct _stat st;
|
||||||
|
if (_stat(path, &st) != 0) {
|
||||||
|
// Directory does not exist, create it
|
||||||
|
if (_mkdir(path) != 0) {
|
||||||
|
perror("_mkdir failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (!(st.st_mode & _S_IFDIR)) {
|
||||||
|
fprintf(stderr, "Path exists but is not a directory\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) != 0) {
|
||||||
|
// Directory does not exist, create it
|
||||||
|
if (mkdir(path, 0755) != 0) {
|
||||||
|
perror("mkdir failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
fprintf(stderr, "Path exists but is not a directory\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *CWD;
|
||||||
|
|
||||||
|
const char CACHE_FOLDER[] = "__arcache__";
|
||||||
|
const char FILE_IDENTIFIER[5] = "ARBI";
|
||||||
|
const char BYTECODE_EXTENTION[] = "arbin";
|
||||||
|
const uint32_t version_number = 0;
|
||||||
|
const char version_string[] = "4.0.0";
|
||||||
|
|
||||||
|
bool file_exists(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) == 0) {
|
||||||
|
return S_ISREG(st.st_mode); // true only if it's a regular file
|
||||||
|
}
|
||||||
|
return false; // doesn't exist, or stat failed
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write_and_hash(FILE *file, XXH64_state_t *state,
|
||||||
|
const void *ptr, size_t size, size_t count) {
|
||||||
|
fwrite(ptr, size, count, file);
|
||||||
|
XXH64_update(state, ptr, size * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void update_hash_from_file(FILE *file, XXH64_state_t *state,
|
||||||
|
size_t size) {
|
||||||
|
char buffer[4096];
|
||||||
|
size_t bytes_read;
|
||||||
|
size_t remaining = size;
|
||||||
|
|
||||||
|
while (remaining > 0 &&
|
||||||
|
(bytes_read =
|
||||||
|
fread(buffer, 1,
|
||||||
|
remaining > sizeof(buffer) ? sizeof(buffer) : remaining,
|
||||||
|
file)) > 0) {
|
||||||
|
XXH64_update(state, buffer, bytes_read);
|
||||||
|
remaining -= bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash,
|
||||||
|
char *source_path) {
|
||||||
|
FILE *bytecode_file = fopen(joined_paths, "rb");
|
||||||
|
if (!bytecode_file) {
|
||||||
|
fprintf(stderr, "cache doesnt exist... compiling from source.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find file size
|
||||||
|
fseek(bytecode_file, 0, SEEK_END);
|
||||||
|
long file_size = ftell(bytecode_file);
|
||||||
|
if (file_size < (long)sizeof(uint64_t)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
fseek(bytecode_file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
// Footer is the last 8 bytes
|
||||||
|
long data_size = file_size - sizeof(uint64_t);
|
||||||
|
|
||||||
|
// Set up hash state
|
||||||
|
XXH64_state_t *state = XXH64_createState();
|
||||||
|
XXH64_reset(state, 0);
|
||||||
|
|
||||||
|
// Hash everything except last 8 bytes
|
||||||
|
update_hash_from_file(bytecode_file, state, data_size);
|
||||||
|
|
||||||
|
// Read stored footer hash
|
||||||
|
uint64_t stored_hash_le;
|
||||||
|
if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) !=
|
||||||
|
sizeof(stored_hash_le)) {
|
||||||
|
XXH64_freeState(state);
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
uint64_t stored_hash = le64toh(stored_hash_le);
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
uint64_t calc_hash = XXH64_digest(state);
|
||||||
|
XXH64_freeState(state);
|
||||||
|
|
||||||
|
if (calc_hash != stored_hash) {
|
||||||
|
fprintf(stderr, "cache hash mismatch (corrupted?)\n");
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now actually parse the file contents
|
||||||
|
fseek(bytecode_file, 0, SEEK_SET); // rewind to start
|
||||||
|
|
||||||
|
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
|
||||||
|
if (fread(&file_identifier_from_cache, 1,
|
||||||
|
sizeof(file_identifier_from_cache) - 1,
|
||||||
|
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
|
||||||
|
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
|
||||||
|
sizeof(file_identifier_from_cache)) != 0) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read_version;
|
||||||
|
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
|
||||||
|
sizeof(read_version)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
read_version = le32toh(read_version);
|
||||||
|
|
||||||
|
if (read_version != version_number) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t read_hash;
|
||||||
|
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
|
||||||
|
sizeof(read_hash)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
read_hash = le64toh(read_hash);
|
||||||
|
|
||||||
|
if (read_hash != hash) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t register_count;
|
||||||
|
if (fread(®ister_count, 1, sizeof(register_count), bytecode_file) !=
|
||||||
|
sizeof(register_count)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t constantsSize;
|
||||||
|
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
|
||||||
|
sizeof(constantsSize)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
constantsSize = le64toh(constantsSize);
|
||||||
|
|
||||||
|
uint64_t bytecodeSize;
|
||||||
|
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
|
||||||
|
sizeof(bytecodeSize)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
bytecodeSize = le64toh(bytecodeSize);
|
||||||
|
|
||||||
|
*translated_dest = init_translator(source_path);
|
||||||
|
|
||||||
|
translated_dest->registerCount = register_count;
|
||||||
|
|
||||||
|
arena_resize(&translated_dest->constants, constantsSize);
|
||||||
|
|
||||||
|
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
|
||||||
|
constantsSize) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
translated_dest->constants.size = constantsSize;
|
||||||
|
|
||||||
|
darray_resize(&translated_dest->bytecode, bytecodeSize);
|
||||||
|
|
||||||
|
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
|
||||||
|
bytecodeSize) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
translated_dest->bytecode.size = bytecodeSize;
|
||||||
|
|
||||||
|
fprintf(stderr, "cache exists and is valid, so will be used.\n");
|
||||||
|
fclose(bytecode_file);
|
||||||
|
return 0;
|
||||||
|
FAILED:
|
||||||
|
fprintf(stderr, "cache is invalid... compiling from source.\n");
|
||||||
|
fclose(bytecode_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Translated load_argon_file(char *path, ArErr *err) {
|
||||||
|
clock_t start, end;
|
||||||
|
clock_t beginning = clock();
|
||||||
|
double time_spent, total_time_spent = 0;
|
||||||
|
|
||||||
|
const char *basename_ptr;
|
||||||
|
size_t basename_length;
|
||||||
|
cwk_path_get_basename(path, &basename_ptr, &basename_length);
|
||||||
|
|
||||||
|
if (!basename_ptr) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'",
|
||||||
|
path);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
|
||||||
|
char basename[FILENAME_MAX];
|
||||||
|
memcpy(basename, basename_ptr, basename_length);
|
||||||
|
|
||||||
|
size_t parent_directory_length;
|
||||||
|
cwk_path_get_dirname(path, &parent_directory_length);
|
||||||
|
|
||||||
|
char parent_directory[FILENAME_MAX];
|
||||||
|
memcpy(parent_directory, path, parent_directory_length);
|
||||||
|
parent_directory[parent_directory_length] = '\0';
|
||||||
|
|
||||||
|
char cache_folder_path[FILENAME_MAX];
|
||||||
|
cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path,
|
||||||
|
sizeof(cache_folder_path));
|
||||||
|
|
||||||
|
char cache_file_path[FILENAME_MAX];
|
||||||
|
cwk_path_join(cache_folder_path, basename, cache_file_path,
|
||||||
|
sizeof(cache_file_path));
|
||||||
|
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION,
|
||||||
|
cache_file_path, sizeof(cache_file_path));
|
||||||
|
|
||||||
|
FILE *file = fopen(path, "r");
|
||||||
|
if (!file) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to open file '%s'",
|
||||||
|
path);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH3_state_t *hash_state = XXH3_createState();
|
||||||
|
XXH3_64bits_reset(hash_state);
|
||||||
|
|
||||||
|
char buffer[8192];
|
||||||
|
size_t bytes;
|
||||||
|
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) {
|
||||||
|
XXH3_64bits_update(hash_state, buffer, bytes);
|
||||||
|
}
|
||||||
|
rewind(file);
|
||||||
|
uint64_t hash = XXH3_64bits_digest(hash_state);
|
||||||
|
XXH3_freeState(hash_state);
|
||||||
|
|
||||||
|
Translated translated;
|
||||||
|
|
||||||
|
if (load_cache(&translated, cache_file_path, hash, path) != 0) {
|
||||||
|
|
||||||
|
DArray tokens;
|
||||||
|
darray_init(&tokens, sizeof(Token));
|
||||||
|
|
||||||
|
LexerState state = {path, file, 0, 0, &tokens};
|
||||||
|
start = clock();
|
||||||
|
*err = lexer(state);
|
||||||
|
if (err->exists) {
|
||||||
|
darray_free(&tokens, free_token);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent);
|
||||||
|
fclose(state.file);
|
||||||
|
|
||||||
|
DArray ast;
|
||||||
|
|
||||||
|
darray_init(&ast, sizeof(ParsedValue));
|
||||||
|
|
||||||
|
start = clock();
|
||||||
|
*err = parser(path, &ast, &tokens, false);
|
||||||
|
darray_free(&tokens, free_token);
|
||||||
|
if (err->exists) {
|
||||||
|
darray_free(&ast, free_parsed);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Parser time taken: %f seconds\n", time_spent);
|
||||||
|
|
||||||
|
start = clock();
|
||||||
|
|
||||||
|
translated = init_translator(path);
|
||||||
|
*err = translate(&translated, &ast);
|
||||||
|
darray_free(&ast, free_parsed);
|
||||||
|
if (err->exists) {
|
||||||
|
darray_free(&translated.bytecode, NULL);
|
||||||
|
free(translated.constants.data);
|
||||||
|
hashmap_free(translated.constants.hashmap, NULL);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Translation time taken: %f seconds\n", time_spent);
|
||||||
|
#if defined(__linux__)
|
||||||
|
malloc_trim(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ensure_dir_exists(cache_folder_path);
|
||||||
|
|
||||||
|
file = fopen(cache_file_path, "wb");
|
||||||
|
|
||||||
|
uint64_t constantsSize = translated.constants.size;
|
||||||
|
uint64_t bytecodeSize = translated.bytecode.size;
|
||||||
|
|
||||||
|
uint32_t version_number_htole32ed = htole32(version_number);
|
||||||
|
uint64_t net_hash = htole64(hash);
|
||||||
|
constantsSize = htole64(constantsSize);
|
||||||
|
bytecodeSize = htole64(bytecodeSize);
|
||||||
|
|
||||||
|
XXH64_state_t *hash_state = XXH64_createState();
|
||||||
|
XXH64_reset(hash_state, 0);
|
||||||
|
|
||||||
|
write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char),
|
||||||
|
strlen(FILE_IDENTIFIER));
|
||||||
|
write_and_hash(file, hash_state, &version_number_htole32ed,
|
||||||
|
sizeof(uint32_t), 1);
|
||||||
|
write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1);
|
||||||
|
write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t),
|
||||||
|
1);
|
||||||
|
write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1);
|
||||||
|
write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1);
|
||||||
|
write_and_hash(file, hash_state, translated.constants.data, 1,
|
||||||
|
translated.constants.size);
|
||||||
|
write_and_hash(file, hash_state, translated.bytecode.data,
|
||||||
|
translated.bytecode.element_size, translated.bytecode.size);
|
||||||
|
|
||||||
|
// Finalize the hash
|
||||||
|
uint64_t file_hash = XXH64_digest(hash_state);
|
||||||
|
XXH64_freeState(hash_state);
|
||||||
|
|
||||||
|
// Convert to little-endian before writing if needed
|
||||||
|
uint64_t file_hash_le = htole64(file_hash);
|
||||||
|
fwrite(&file_hash_le, sizeof(file_hash_le), 1, file);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
hashmap_free(translated.constants.hashmap, NULL);
|
||||||
|
Translated gc_translated = {
|
||||||
|
translated.registerCount, translated.registerAssignment, NULL, {}, {},
|
||||||
|
translated.path};
|
||||||
|
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity);
|
||||||
|
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
||||||
|
translated.bytecode.capacity);
|
||||||
|
gc_translated.bytecode.element_size = translated.bytecode.element_size;
|
||||||
|
gc_translated.bytecode.size = translated.bytecode.size;
|
||||||
|
gc_translated.bytecode.resizable = false;
|
||||||
|
gc_translated.bytecode.capacity =
|
||||||
|
translated.bytecode.size * translated.bytecode.element_size;
|
||||||
|
gc_translated.constants.data = ar_alloc_atomic(translated.constants.capacity);
|
||||||
|
memcpy(gc_translated.constants.data, translated.constants.data,
|
||||||
|
translated.constants.capacity);
|
||||||
|
gc_translated.constants.size = translated.constants.size;
|
||||||
|
gc_translated.constants.capacity = translated.constants.capacity;
|
||||||
|
free(translated.bytecode.data);
|
||||||
|
free(translated.constants.data);
|
||||||
|
total_time_spent = (double)(clock() - beginning) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "total time taken loading file (%s): %f seconds\n", path,
|
||||||
|
total_time_spent);
|
||||||
|
return gc_translated;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *PRE_PATHS_TO_TEST[] = {"", "", "argon_modules", "argon_modules"};
|
||||||
|
const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST)/sizeof(char *)] = {"", "init.ar", "",
|
||||||
|
"init.ar"};
|
||||||
|
|
||||||
|
struct hashmap *importing_hash_table = NULL;
|
||||||
|
struct hashmap_GC *imported_hash_table = NULL;
|
||||||
|
|
||||||
|
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||||
|
char path[FILENAME_MAX];
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST)/sizeof(char *); i++) {
|
||||||
|
cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path, sizeof(path));
|
||||||
|
cwk_path_get_absolute(path, path_relative, path, sizeof(path));
|
||||||
|
cwk_path_get_absolute(path, POST_PATHS_TO_TEST[i], path, sizeof(path));
|
||||||
|
if (file_exists(path)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to find file '%s'",
|
||||||
|
path_relative);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!importing_hash_table) importing_hash_table = createHashmap();
|
||||||
|
uint64_t hash = siphash64_bytes(path, strlen(path), siphash_key);
|
||||||
|
hashmap_insert(importing_hash_table, hash, path, (void*)true, 0);
|
||||||
|
Translated translated = load_argon_file(path, err);
|
||||||
|
if (err->exists) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
clock_t start = clock(), end;
|
||||||
|
RuntimeState state = init_runtime_state(translated, path);
|
||||||
|
Stack *main_scope = create_scope(Global_Scope, true);
|
||||||
|
runtime(translated, state, main_scope, err);
|
||||||
|
if (err->exists) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Execution time taken: %f seconds\n", time_spent);
|
||||||
|
hashmap_insert(importing_hash_table, hash, path, (void*)false, 0);
|
||||||
|
if (!imported_hash_table) imported_hash_table = createHashmap_GC();
|
||||||
|
hashmap_insert_GC(imported_hash_table, hash, path, main_scope, 0);
|
||||||
|
return main_scope;
|
||||||
|
}
|
||||||
17
src/import.h
Normal file
17
src/import.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMPORT_H
|
||||||
|
#define IMPORT_H
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
extern char*CWD;
|
||||||
|
|
||||||
|
extern const char version_string[];
|
||||||
|
|
||||||
|
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err);
|
||||||
|
|
||||||
|
#endif // IMPORT_H
|
||||||
@@ -32,13 +32,6 @@ int yywrap(void * unused_param) {
|
|||||||
":" { return TOKEN_COLON; }
|
":" { return TOKEN_COLON; }
|
||||||
|
|
||||||
"=" { return TOKEN_ASSIGN; }
|
"=" { return TOKEN_ASSIGN; }
|
||||||
"+=" { return TOKEN_ASSIGN_PLUS; }
|
|
||||||
"-=" { return TOKEN_ASSIGN_MINUS; }
|
|
||||||
"//=" { return TOKEN_ASSIGN_FLOORDIV; }
|
|
||||||
"/=" { return TOKEN_ASSIGN_SLASH; }
|
|
||||||
"%=" { return TOKEN_ASSIGN_MODULO; }
|
|
||||||
"*=" { return TOKEN_ASSIGN_STAR; }
|
|
||||||
"^=" { return TOKEN_ASSIGN_CARET; }
|
|
||||||
|
|
||||||
"not"[ \t]+"in" { return TOKEN_NOT_IN; }
|
"not"[ \t]+"in" { return TOKEN_NOT_IN; }
|
||||||
"in" { return TOKEN_IN; }
|
"in" { return TOKEN_IN; }
|
||||||
|
|||||||
@@ -17,13 +17,6 @@ typedef enum {
|
|||||||
TOKEN_INDENT,
|
TOKEN_INDENT,
|
||||||
|
|
||||||
TOKEN_ASSIGN,
|
TOKEN_ASSIGN,
|
||||||
TOKEN_ASSIGN_PLUS,
|
|
||||||
TOKEN_ASSIGN_MINUS,
|
|
||||||
TOKEN_ASSIGN_FLOORDIV,
|
|
||||||
TOKEN_ASSIGN_SLASH,
|
|
||||||
TOKEN_ASSIGN_MODULO,
|
|
||||||
TOKEN_ASSIGN_STAR,
|
|
||||||
TOKEN_ASSIGN_CARET,
|
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
TOKEN_CARET, // ^ (Exponentiation)
|
TOKEN_CARET, // ^ (Exponentiation)
|
||||||
@@ -31,8 +24,8 @@ typedef enum {
|
|||||||
TOKEN_SLASH, // / (Division)
|
TOKEN_SLASH, // / (Division)
|
||||||
TOKEN_FLOORDIV, // // (Floor Division)
|
TOKEN_FLOORDIV, // // (Floor Division)
|
||||||
TOKEN_MODULO, // % (Modulo)
|
TOKEN_MODULO, // % (Modulo)
|
||||||
TOKEN_PLUS, // + (Addition)
|
|
||||||
TOKEN_MINUS, // - (Subtraction)
|
TOKEN_MINUS, // - (Subtraction)
|
||||||
|
TOKEN_PLUS, // + (Addition)
|
||||||
TOKEN_LT, // <
|
TOKEN_LT, // <
|
||||||
TOKEN_GT, // >
|
TOKEN_GT, // >
|
||||||
TOKEN_LE, // <=
|
TOKEN_LE, // <=
|
||||||
|
|||||||
435
src/main.c
435
src/main.c
@@ -4,70 +4,23 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "arobject.h"
|
#include "err.h"
|
||||||
#include "dynamic_array/darray.h"
|
|
||||||
#include "hashmap/hashmap.h"
|
#include "hashmap/hashmap.h"
|
||||||
#include "lexer/lexer.h"
|
#include "import.h"
|
||||||
#include "lexer/token.h"
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "parser/parser.h"
|
#include "runtime/objects/object.h"
|
||||||
#include "runtime/runtime.h"
|
#include "runtime/runtime.h"
|
||||||
#include "translator/translator.h"
|
#include "shell.h"
|
||||||
|
|
||||||
#include "../external/xxhash/xxhash.h"
|
|
||||||
#include "hash_data/hash_data.h"
|
#include "hash_data/hash_data.h"
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h> // for _mkdir
|
|
||||||
#include <sys/stat.h> // for _stat
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
#include "../external/cwalk/include/cwalk.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <limits.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
#include "err.h"
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
|
||||||
|
|
||||||
// Windows / MinGW usually uses little-endian, so these can be no-ops
|
|
||||||
// But define them explicitly to avoid implicit declaration warnings
|
|
||||||
|
|
||||||
static inline uint32_t le32toh(uint32_t x) { return x; }
|
|
||||||
static inline uint64_t le64toh(uint64_t x) { return x; }
|
|
||||||
static inline uint32_t htole32(uint32_t x) { return x; }
|
|
||||||
static inline uint64_t htole64(uint64_t x) { return x; }
|
|
||||||
|
|
||||||
#elif defined(__linux__)
|
|
||||||
#include <endian.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#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
|
|
||||||
#else
|
|
||||||
#error "Unsupported platform"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *get_current_directory() {
|
char *get_current_directory() {
|
||||||
@@ -98,385 +51,29 @@ char *get_current_directory() {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ensure_dir_exists(const char *path) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
struct _stat st;
|
|
||||||
if (_stat(path, &st) != 0) {
|
|
||||||
// Directory does not exist, create it
|
|
||||||
if (_mkdir(path) != 0) {
|
|
||||||
perror("_mkdir failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (!(st.st_mode & _S_IFDIR)) {
|
|
||||||
fprintf(stderr, "Path exists but is not a directory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
struct stat st;
|
|
||||||
if (stat(path, &st) != 0) {
|
|
||||||
// Directory does not exist, create it
|
|
||||||
if (mkdir(path, 0755) != 0) {
|
|
||||||
perror("mkdir failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (!S_ISDIR(st.st_mode)) {
|
|
||||||
fprintf(stderr, "Path exists but is not a directory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 FILE_IDENTIFIER[5] = "ARBI";
|
|
||||||
const char BYTECODE_EXTENTION[] = "arbin";
|
|
||||||
const uint32_t version_number = 0;
|
|
||||||
|
|
||||||
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash,
|
|
||||||
char *source_path) {
|
|
||||||
FILE *bytecode_file = fopen(joined_paths, "rb");
|
|
||||||
if (!bytecode_file) {
|
|
||||||
fprintf(stderr,"cache doesnt exist... compiling from source.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find file size
|
|
||||||
fseek(bytecode_file, 0, SEEK_END);
|
|
||||||
long file_size = ftell(bytecode_file);
|
|
||||||
if (file_size < (long)sizeof(uint64_t)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
fseek(bytecode_file, 0, SEEK_SET);
|
|
||||||
|
|
||||||
// Footer is the last 8 bytes
|
|
||||||
long data_size = file_size - sizeof(uint64_t);
|
|
||||||
|
|
||||||
// Set up hash state
|
|
||||||
XXH64_state_t *state = XXH64_createState();
|
|
||||||
XXH64_reset(state, 0);
|
|
||||||
|
|
||||||
// Hash everything except last 8 bytes
|
|
||||||
update_hash_from_file(bytecode_file, state, data_size);
|
|
||||||
|
|
||||||
// Read stored footer hash
|
|
||||||
uint64_t stored_hash_le;
|
|
||||||
if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) !=
|
|
||||||
sizeof(stored_hash_le)) {
|
|
||||||
XXH64_freeState(state);
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
uint64_t stored_hash = le64toh(stored_hash_le);
|
|
||||||
|
|
||||||
// Compare
|
|
||||||
uint64_t calc_hash = XXH64_digest(state);
|
|
||||||
XXH64_freeState(state);
|
|
||||||
|
|
||||||
if (calc_hash != stored_hash) {
|
|
||||||
fprintf(stderr,"cache hash mismatch (corrupted?)\n");
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now actually parse the file contents
|
|
||||||
fseek(bytecode_file, 0, SEEK_SET); // rewind to start
|
|
||||||
|
|
||||||
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
|
|
||||||
if (fread(&file_identifier_from_cache, 1,
|
|
||||||
sizeof(file_identifier_from_cache) - 1,
|
|
||||||
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
|
|
||||||
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
|
|
||||||
sizeof(file_identifier_from_cache)) != 0) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t read_version;
|
|
||||||
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
|
|
||||||
sizeof(read_version)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
read_version = le32toh(read_version);
|
|
||||||
|
|
||||||
if (read_version != version_number) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t read_hash;
|
|
||||||
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
|
|
||||||
sizeof(read_hash)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
read_hash = le64toh(read_hash);
|
|
||||||
|
|
||||||
if (read_hash != hash) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t register_count;
|
|
||||||
if (fread(®ister_count, 1, sizeof(register_count), bytecode_file) !=
|
|
||||||
sizeof(register_count)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t constantsSize;
|
|
||||||
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
|
|
||||||
sizeof(constantsSize)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
constantsSize = le64toh(constantsSize);
|
|
||||||
|
|
||||||
uint64_t bytecodeSize;
|
|
||||||
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
|
|
||||||
sizeof(bytecodeSize)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
bytecodeSize = le64toh(bytecodeSize);
|
|
||||||
|
|
||||||
*translated_dest = init_translator(source_path);
|
|
||||||
|
|
||||||
arena_resize(&translated_dest->constants, constantsSize);
|
|
||||||
|
|
||||||
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
|
|
||||||
constantsSize) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
darray_resize(&translated_dest->bytecode, bytecodeSize);
|
|
||||||
|
|
||||||
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
|
|
||||||
bytecodeSize) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr,"cache exists and is valid, so will be used.\n");
|
|
||||||
fclose(bytecode_file);
|
|
||||||
return 0;
|
|
||||||
FAILED:
|
|
||||||
fprintf(stderr,"cache is invalid... compiling from source.\n");
|
|
||||||
fclose(bytecode_file);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Execution execute(char *path, Stack *stack) {
|
|
||||||
clock_t start, end;
|
|
||||||
double time_spent, total_time_spent = 0;
|
|
||||||
|
|
||||||
const char *basename_ptr;
|
|
||||||
size_t basename_length;
|
|
||||||
cwk_path_get_basename(path, &basename_ptr, &basename_length);
|
|
||||||
|
|
||||||
if (!basename_ptr)
|
|
||||||
return (Execution){create_err(0, 0, 0, NULL, "Path Error",
|
|
||||||
"path has no basename '%s'", path),
|
|
||||||
(Stack){NULL, NULL}};
|
|
||||||
|
|
||||||
char basename[FILENAME_MAX];
|
|
||||||
memcpy(basename, basename_ptr, basename_length);
|
|
||||||
|
|
||||||
size_t parent_directory_length;
|
|
||||||
cwk_path_get_dirname(path, &parent_directory_length);
|
|
||||||
|
|
||||||
char parent_directory[FILENAME_MAX];
|
|
||||||
memcpy(parent_directory, path, parent_directory_length);
|
|
||||||
parent_directory[parent_directory_length] = '\0';
|
|
||||||
|
|
||||||
char cache_folder_path[FILENAME_MAX];
|
|
||||||
cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path,
|
|
||||||
sizeof(cache_folder_path));
|
|
||||||
|
|
||||||
char cache_file_path[FILENAME_MAX];
|
|
||||||
cwk_path_join(cache_folder_path, basename, cache_file_path,
|
|
||||||
sizeof(cache_file_path));
|
|
||||||
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION,
|
|
||||||
cache_file_path, sizeof(cache_file_path));
|
|
||||||
|
|
||||||
FILE *file = fopen(path, "r");
|
|
||||||
if (!file) {
|
|
||||||
return (Execution){create_err(0, 0, 0, NULL, "File Error",
|
|
||||||
"Unable to open file '%s'", path),
|
|
||||||
(Stack){NULL, NULL}};
|
|
||||||
}
|
|
||||||
|
|
||||||
XXH3_state_t *hash_state = XXH3_createState();
|
|
||||||
XXH3_64bits_reset(hash_state);
|
|
||||||
|
|
||||||
char buffer[8192];
|
|
||||||
size_t bytes;
|
|
||||||
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) {
|
|
||||||
XXH3_64bits_update(hash_state, buffer, bytes);
|
|
||||||
}
|
|
||||||
rewind(file);
|
|
||||||
uint64_t hash = XXH3_64bits_digest(hash_state);
|
|
||||||
XXH3_freeState(hash_state);
|
|
||||||
|
|
||||||
Translated translated;
|
|
||||||
|
|
||||||
if (load_cache(&translated, cache_file_path, hash, path) != 0) {
|
|
||||||
|
|
||||||
DArray tokens;
|
|
||||||
darray_init(&tokens, sizeof(Token));
|
|
||||||
|
|
||||||
LexerState state = {path, file, 0, 0, &tokens};
|
|
||||||
start = clock();
|
|
||||||
ArErr err = lexer(state);
|
|
||||||
if (err.exists) {
|
|
||||||
darray_free(&tokens, free_token);
|
|
||||||
return (Execution){err, (Stack){NULL, NULL}};
|
|
||||||
}
|
|
||||||
end = clock();
|
|
||||||
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
|
||||||
total_time_spent += time_spent;
|
|
||||||
fprintf(stderr,"Lexer time taken: %f seconds\n", time_spent);
|
|
||||||
fclose(state.file);
|
|
||||||
|
|
||||||
DArray ast;
|
|
||||||
|
|
||||||
darray_init(&ast, sizeof(ParsedValue));
|
|
||||||
|
|
||||||
start = clock();
|
|
||||||
err = parser(path, &ast, &tokens, false);
|
|
||||||
if (err.exists) {
|
|
||||||
darray_free(&tokens, free_token);
|
|
||||||
darray_free(&ast, free_parsed);
|
|
||||||
return (Execution){err, (Stack){NULL, NULL}};
|
|
||||||
}
|
|
||||||
end = clock();
|
|
||||||
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
|
||||||
total_time_spent += time_spent;
|
|
||||||
fprintf(stderr,"Parser time taken: %f seconds\n", time_spent);
|
|
||||||
darray_free(&tokens, free_token);
|
|
||||||
|
|
||||||
start = clock();
|
|
||||||
|
|
||||||
translated = init_translator(path);
|
|
||||||
err = translate(&translated, &ast);
|
|
||||||
if (err.exists) {
|
|
||||||
darray_free(&translated.bytecode, NULL);
|
|
||||||
free(translated.constants.data);
|
|
||||||
hashmap_free(translated.constants.hashmap, NULL);
|
|
||||||
darray_free(&ast, free_parsed);
|
|
||||||
return (Execution){err, (Stack){NULL, NULL}};
|
|
||||||
}
|
|
||||||
end = clock();
|
|
||||||
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
|
||||||
total_time_spent += time_spent;
|
|
||||||
fprintf(stderr,"Translation time taken: %f seconds\n", time_spent);
|
|
||||||
|
|
||||||
darray_free(&ast, free_parsed);
|
|
||||||
#if defined(__linux__)
|
|
||||||
malloc_trim(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ensure_dir_exists(cache_folder_path);
|
|
||||||
|
|
||||||
file = fopen(cache_file_path, "wb");
|
|
||||||
|
|
||||||
uint64_t constantsSize = translated.constants.size;
|
|
||||||
uint64_t bytecodeSize = translated.bytecode.size;
|
|
||||||
|
|
||||||
uint32_t version_number_htole32ed = htole32(version_number);
|
|
||||||
uint64_t net_hash = htole64(hash);
|
|
||||||
constantsSize = htole64(constantsSize);
|
|
||||||
bytecodeSize = htole64(bytecodeSize);
|
|
||||||
|
|
||||||
XXH64_state_t *hash_state = XXH64_createState();
|
|
||||||
XXH64_reset(hash_state, 0);
|
|
||||||
|
|
||||||
write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char),
|
|
||||||
strlen(FILE_IDENTIFIER));
|
|
||||||
write_and_hash(file, hash_state, &version_number_htole32ed,
|
|
||||||
sizeof(uint32_t), 1);
|
|
||||||
write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1);
|
|
||||||
write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t),
|
|
||||||
1);
|
|
||||||
write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1);
|
|
||||||
write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1);
|
|
||||||
write_and_hash(file, hash_state, translated.constants.data, 1,
|
|
||||||
translated.constants.size);
|
|
||||||
write_and_hash(file, hash_state, translated.bytecode.data,
|
|
||||||
translated.bytecode.element_size, translated.bytecode.size);
|
|
||||||
|
|
||||||
// Finalize the hash
|
|
||||||
uint64_t file_hash = XXH64_digest(hash_state);
|
|
||||||
XXH64_freeState(hash_state);
|
|
||||||
|
|
||||||
// Convert to little-endian before writing if needed
|
|
||||||
uint64_t file_hash_le = htole64(file_hash);
|
|
||||||
fwrite(&file_hash_le, sizeof(file_hash_le), 1, file);
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
hashmap_free(translated.constants.hashmap, NULL);
|
|
||||||
Translated gc_translated = {
|
|
||||||
translated.registerCount, NULL, {}, {}, translated.path};
|
|
||||||
gc_translated.bytecode.data = ar_alloc(translated.bytecode.capacity);
|
|
||||||
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
|
||||||
translated.bytecode.capacity);
|
|
||||||
gc_translated.bytecode.element_size = translated.bytecode.element_size;
|
|
||||||
gc_translated.bytecode.size = translated.bytecode.size;
|
|
||||||
gc_translated.bytecode.resizable = false;
|
|
||||||
gc_translated.bytecode.capacity =
|
|
||||||
translated.bytecode.size * translated.bytecode.element_size;
|
|
||||||
gc_translated.constants.data = ar_alloc(translated.constants.capacity);
|
|
||||||
memcpy(gc_translated.constants.data, translated.constants.data,
|
|
||||||
translated.constants.capacity);
|
|
||||||
gc_translated.constants.size = translated.constants.size;
|
|
||||||
gc_translated.constants.capacity = translated.constants.capacity;
|
|
||||||
darray_free(&translated.bytecode, NULL);
|
|
||||||
free(translated.constants.data);
|
|
||||||
|
|
||||||
start = clock();
|
|
||||||
RuntimeState state = init_runtime_state(gc_translated, path);
|
|
||||||
Stack *main_scope = create_scope(stack);
|
|
||||||
ArErr err = runtime(gc_translated, state, main_scope);
|
|
||||||
end = clock();
|
|
||||||
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
|
||||||
total_time_spent += time_spent;
|
|
||||||
fprintf(stderr,"Execution time taken: %f seconds\n", time_spent);
|
|
||||||
fprintf(stderr,"total time taken: %f seconds\n", total_time_spent);
|
|
||||||
|
|
||||||
return (Execution){err, *main_scope};
|
|
||||||
}
|
|
||||||
|
|
||||||
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_built_in_field_hashes();
|
||||||
bootstrap_types();
|
bootstrap_types();
|
||||||
bootstrap_globals();
|
bootstrap_globals();
|
||||||
char *CWD = get_current_directory();
|
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
return -1;
|
return shell();
|
||||||
|
CWD = get_current_directory();
|
||||||
char *path_non_absolute = argv[1];
|
char *path_non_absolute = argv[1];
|
||||||
char path[FILENAME_MAX];
|
ArErr err = no_err;
|
||||||
cwk_path_get_absolute(CWD, path_non_absolute, path, sizeof(path));
|
ar_import(CWD, path_non_absolute, &err);
|
||||||
|
if (err.exists) {
|
||||||
|
output_err(err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
free(CWD);
|
free(CWD);
|
||||||
Execution resp = execute(path, Global_Scope);
|
ar_memory_shutdown();
|
||||||
if (runtime_hash_table)
|
if (runtime_hash_table)
|
||||||
hashmap_free(runtime_hash_table, NULL);
|
hashmap_free(runtime_hash_table, NULL);
|
||||||
if (resp.err.exists) {
|
if (err.exists) {
|
||||||
output_err(resp.err);
|
output_err(err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// Your main thread code
|
// Your main thread code
|
||||||
|
|||||||
28
src/memory.c
28
src/memory.c
@@ -6,10 +6,12 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include <gc.h>
|
#include <gc.h>
|
||||||
#include <gmp.h>
|
#include <gc/gc.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> // for malloc/free (temp arena fallback)
|
#include <stdlib.h> // for malloc/free (temp arena fallback)
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
void *checked_malloc(size_t size) {
|
void *checked_malloc(size_t size) {
|
||||||
void *ptr = malloc(size);
|
void *ptr = malloc(size);
|
||||||
@@ -20,19 +22,23 @@ void *checked_malloc(size_t size) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *gmp_gc_realloc(void *ptr, size_t old_size, size_t new_size) {
|
struct allocation*memory_allocations = NULL;
|
||||||
(void)old_size; // Ignore old_size, Boehm doesn't need it
|
size_t memory_allocations_size = 0;
|
||||||
return GC_realloc(ptr, new_size);
|
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
}
|
|
||||||
|
|
||||||
void gmp_gc_free(void *ptr, size_t size) {
|
|
||||||
(void)size; // Boehm GC manages this itself
|
|
||||||
// No-op — memory will be collected automatically
|
|
||||||
GC_FREE(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ar_memory_init() {
|
void ar_memory_init() {
|
||||||
GC_INIT();
|
GC_INIT();
|
||||||
|
// memory_allocations_size = 8;
|
||||||
|
// memory_allocations = malloc(memory_allocations_size*sizeof(struct allocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ar_memory_shutdown() {
|
||||||
|
// for (size_t i = 0; i<memory_allocations_size;i++) {
|
||||||
|
// if (memory_allocations[i].status != allocation_fully_freed) {
|
||||||
|
// free(memory_allocations[i].ptr);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// free(memory_allocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ar_alloc(size_t size) { return GC_MALLOC(size); }
|
void *ar_alloc(size_t size) { return GC_MALLOC(size); }
|
||||||
|
|||||||
14
src/memory.h
14
src/memory.h
@@ -8,10 +8,23 @@
|
|||||||
#define ARGON_MEMORY_H
|
#define ARGON_MEMORY_H
|
||||||
|
|
||||||
#include <stddef.h> // for size_t
|
#include <stddef.h> // for size_t
|
||||||
|
#include <stdbool.h>
|
||||||
#include <gc/gc.h>
|
#include <gc/gc.h>
|
||||||
|
|
||||||
// GC-managed allocations
|
// GC-managed allocations
|
||||||
|
|
||||||
|
typedef enum allocation_status {
|
||||||
|
allocation_used,
|
||||||
|
allocation_soft_free, // avaiable for use, since it hasnt been freed but isnt in use.
|
||||||
|
allocation_fully_freed,
|
||||||
|
} allocation_status;
|
||||||
|
|
||||||
|
struct allocation {
|
||||||
|
void*ptr;
|
||||||
|
size_t size;
|
||||||
|
allocation_status status;
|
||||||
|
};
|
||||||
|
|
||||||
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
||||||
GC_finalization_proc *old_fn, void **old_client_data);
|
GC_finalization_proc *old_fn, void **old_client_data);
|
||||||
void *ar_alloc(size_t size);
|
void *ar_alloc(size_t size);
|
||||||
@@ -21,6 +34,7 @@ char *ar_strdup(const char *str);
|
|||||||
|
|
||||||
// Memory init/shutdown
|
// Memory init/shutdown
|
||||||
void ar_memory_init();
|
void ar_memory_init();
|
||||||
|
void ar_memory_shutdown();
|
||||||
|
|
||||||
void *checked_malloc(size_t size);
|
void *checked_malloc(size_t size);
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,12 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
|||||||
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->to_access = *to_access;
|
|
||||||
parsedValue->type = AST_ACCESS;
|
|
||||||
parsedValue->data = parsedAccess;
|
|
||||||
free(to_access);
|
|
||||||
darray_init(&parsedAccess->access, sizeof(ParsedValue));
|
|
||||||
if (first_token->type == TOKEN_DOT) {
|
if (first_token->type == TOKEN_DOT) {
|
||||||
|
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
||||||
|
parsedAccess->to_access = to_access;
|
||||||
|
parsedAccess->access = NULL;
|
||||||
|
parsedValue->type = AST_ACCESS;
|
||||||
|
parsedValue->data = parsedAccess;
|
||||||
ArErr err = error_if_finished(file, tokens, index);
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
if (err.exists) {
|
if (err.exists) {
|
||||||
free_parsed(parsedValue);
|
free_parsed(parsedValue);
|
||||||
@@ -32,6 +31,14 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
|||||||
return (ParsedValueReturn){err, NULL};
|
return (ParsedValueReturn){err, NULL};
|
||||||
}
|
}
|
||||||
Token *token = darray_get(tokens, *index);
|
Token *token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_IDENTIFIER) {
|
||||||
|
free_parsed(parsedValue);
|
||||||
|
free(parsedValue);
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected identifier after dot"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
parsedAccess->line = token->line;
|
parsedAccess->line = token->line;
|
||||||
parsedAccess->column = token->column;
|
parsedAccess->column = token->column;
|
||||||
parsedAccess->length = token->length;
|
parsedAccess->length = token->length;
|
||||||
@@ -41,59 +48,7 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
|||||||
free(parsedValue);
|
free(parsedValue);
|
||||||
return parsedString;
|
return parsedString;
|
||||||
}
|
}
|
||||||
darray_push(&parsedAccess->access, parsedString.value);
|
parsedAccess->access = parsedString.value;
|
||||||
free(parsedString.value);
|
|
||||||
parsedAccess->access_fields = true;
|
|
||||||
} else {
|
|
||||||
parsedAccess->line = first_token->line;
|
|
||||||
parsedAccess->column = first_token->column;
|
|
||||||
parsedAccess->length = first_token->length;
|
|
||||||
parsedAccess->access_fields = false;
|
|
||||||
Token *token = first_token;
|
|
||||||
while (true) {
|
|
||||||
skip_newlines_and_indents(tokens, index);
|
|
||||||
ArErr err = error_if_finished(file, tokens, index);
|
|
||||||
if (err.exists) {
|
|
||||||
free_parsed(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);
|
|
||||||
err = error_if_finished(file, tokens, index);
|
|
||||||
if (err.exists) {
|
|
||||||
free_parsed(parsedValue);
|
|
||||||
free(parsedValue);
|
|
||||||
return (ParsedValueReturn){err, NULL};
|
|
||||||
}
|
|
||||||
token = darray_get(tokens, *index);
|
|
||||||
if (token->type == TOKEN_RBRACKET) {
|
|
||||||
break;
|
|
||||||
} else if (token->type != TOKEN_COLON) {
|
|
||||||
free_parsed(parsedValue);
|
|
||||||
free(parsedValue);
|
|
||||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
|
||||||
token->length, file,
|
|
||||||
"Syntax Error", "expected colon"),
|
|
||||||
NULL};
|
|
||||||
}
|
|
||||||
(*index)++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(*index)++;
|
(*index)++;
|
||||||
return (ParsedValueReturn){no_err, parsedValue};
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
@@ -102,7 +57,11 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
|||||||
void free_parse_access(void *ptr) {
|
void free_parse_access(void *ptr) {
|
||||||
ParsedValue *parsedValue = ptr;
|
ParsedValue *parsedValue = ptr;
|
||||||
ParsedAccess *parsedAccess = parsedValue->data;
|
ParsedAccess *parsedAccess = parsedValue->data;
|
||||||
free_parsed(&parsedAccess->to_access);
|
free_parsed(parsedAccess->to_access);
|
||||||
darray_free(&parsedAccess->access, free_parsed);
|
free(parsedAccess->to_access);
|
||||||
|
if (parsedAccess->access) {
|
||||||
|
free_parsed(parsedAccess->access);
|
||||||
|
free(parsedAccess->access);
|
||||||
|
}
|
||||||
free(parsedAccess);
|
free(parsedAccess);
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,8 @@
|
|||||||
#include "../../../lexer/token.h" // for Token
|
#include "../../../lexer/token.h" // for Token
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ParsedValue to_access;
|
ParsedValue *to_access;
|
||||||
bool access_fields;
|
ParsedValue *access;
|
||||||
DArray access;
|
|
||||||
size_t line;
|
size_t line;
|
||||||
size_t column;
|
size_t column;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|||||||
@@ -7,25 +7,38 @@
|
|||||||
#include "assign.h"
|
#include "assign.h"
|
||||||
#include "../../../lexer/token.h"
|
#include "../../../lexer/token.h"
|
||||||
#include "../../../memory.h"
|
#include "../../../memory.h"
|
||||||
|
#include "../../function/function.h"
|
||||||
#include "../../parser.h"
|
#include "../../parser.h"
|
||||||
|
#include "../../string/string.h"
|
||||||
|
#include "../access/access.h"
|
||||||
#include "../call/call.h"
|
#include "../call/call.h"
|
||||||
|
#include "../identifier/identifier.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
||||||
ParsedValue *assign_to, size_t *index) {
|
ParsedValue *assign_to, size_t *index) {
|
||||||
Token *token = darray_get(tokens, *index);
|
Token *token = darray_get(tokens, *index);
|
||||||
|
bool is_function = false;
|
||||||
|
char *function_name;
|
||||||
|
bool to_free_function_name = false;
|
||||||
|
DArray function_args;
|
||||||
|
ParsedValue *function_assign_to;
|
||||||
switch (assign_to->type) {
|
switch (assign_to->type) {
|
||||||
case AST_IDENTIFIER:
|
case AST_IDENTIFIER:
|
||||||
case AST_ACCESS:
|
case AST_ACCESS:
|
||||||
break;
|
break;
|
||||||
case AST_CALL:;
|
case AST_CALL:;
|
||||||
ParsedCall *call = assign_to->data;
|
ParsedCall *call = assign_to->data;
|
||||||
|
darray_init(&function_args, sizeof(char *));
|
||||||
for (size_t i = 0; i < call->args.size; i++) {
|
for (size_t i = 0; i < call->args.size; i++) {
|
||||||
if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) {
|
ParsedValue *arg = darray_get(&call->args, i);
|
||||||
|
if (arg->type != AST_IDENTIFIER) {
|
||||||
free_parsed(assign_to);
|
free_parsed(assign_to);
|
||||||
free(assign_to);
|
free(assign_to);
|
||||||
|
darray_free(&function_args, free_parameter);
|
||||||
return (ParsedValueReturn){
|
return (ParsedValueReturn){
|
||||||
create_err(
|
create_err(
|
||||||
token->line, token->column, token->length, file, "Syntax Error",
|
token->line, token->column, token->length, file, "Syntax Error",
|
||||||
@@ -34,6 +47,32 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
|||||||
"only use letters, digits, or _, and can't be keywords."),
|
"only use letters, digits, or _, and can't be keywords."),
|
||||||
NULL};
|
NULL};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *param = strdup(((ParsedIdentifier *)arg->data)->name);
|
||||||
|
darray_push(&function_args, ¶m);
|
||||||
|
}
|
||||||
|
darray_free(&call->args, free_parsed);
|
||||||
|
is_function = true;
|
||||||
|
function_assign_to = call->to_call;
|
||||||
|
switch (function_assign_to->type) {
|
||||||
|
case AST_IDENTIFIER:
|
||||||
|
function_name = ((ParsedIdentifier *)function_assign_to->data)->name;
|
||||||
|
break;
|
||||||
|
case AST_ACCESS:
|
||||||
|
if (((ParsedAccess *)function_assign_to->data)->access->type ==
|
||||||
|
AST_STRING) {
|
||||||
|
ParsedString *name =
|
||||||
|
((ParsedAccess *)function_assign_to->data)->access->data;
|
||||||
|
function_name = checked_malloc(name->length + 1);
|
||||||
|
function_name[name->length] = 0;
|
||||||
|
memcpy(function_name, name->string, name->length);
|
||||||
|
to_free_function_name = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// FALL THROUGH
|
||||||
|
default:
|
||||||
|
function_name = "anonymous";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
@@ -44,35 +83,40 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
|||||||
free(assign_to);
|
free(assign_to);
|
||||||
return (ParsedValueReturn){err, NULL};
|
return (ParsedValueReturn){err, NULL};
|
||||||
}
|
}
|
||||||
|
(*index)++;
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
ParsedValueReturn from = parse_token(file, tokens, index, true);
|
||||||
|
if (from.err.exists) {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
if (!from.value) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected body"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
if (is_function) {
|
||||||
|
from.value =
|
||||||
|
create_parsed_function(function_name, function_args, from.value);
|
||||||
|
if (to_free_function_name) free(function_name);
|
||||||
|
free(assign_to->data);
|
||||||
|
free(assign_to);
|
||||||
|
assign_to = function_assign_to;
|
||||||
|
}
|
||||||
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
|
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
|
||||||
assign->to = assign_to;
|
assign->to = assign_to;
|
||||||
assign->type = token->type;
|
assign->type = 0;
|
||||||
|
assign->from = NULL;
|
||||||
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;
|
||||||
(*index)++;
|
|
||||||
ArErr err = error_if_finished(file, tokens, index);
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
if (err.exists) {
|
if (err.exists) {
|
||||||
free_parsed(parsedValue);
|
free_parsed(parsedValue);
|
||||||
free(parsedValue);
|
free(parsedValue);
|
||||||
return (ParsedValueReturn){err, NULL};
|
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;
|
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};
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
src/parser/not/not.c
Normal file
50
src/parser/not/not.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
#include "not.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
#include "../../memory.h"
|
||||||
|
#include "../parser.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index) {
|
||||||
|
bool invert = true;
|
||||||
|
(*index)++;
|
||||||
|
while (tokens->size > *index) {
|
||||||
|
Token *token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_EXCLAMATION) {
|
||||||
|
ParsedValueReturn value =
|
||||||
|
parse_token_full(file, tokens, index, true, false);
|
||||||
|
if (value.err.exists) {
|
||||||
|
return value;
|
||||||
|
} else if (!value.value) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file,
|
||||||
|
"Syntax Error", "expected value"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
ParsedToBool *parsedToBool = checked_malloc(sizeof(ParsedToBool));
|
||||||
|
parsedToBool->value = value.value;
|
||||||
|
parsedToBool->invert = invert;
|
||||||
|
parsedValue->data = parsedToBool;
|
||||||
|
parsedValue->type = AST_TO_BOOL;
|
||||||
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
|
}
|
||||||
|
invert = !invert;
|
||||||
|
(*index)++;
|
||||||
|
}
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_not(void *ptr) {
|
||||||
|
ParsedValue *parsedValue = ptr;
|
||||||
|
ParsedToBool *parsedToBool = parsedValue->data;
|
||||||
|
free_parsed(parsedToBool->value);
|
||||||
|
free(parsedToBool->value);
|
||||||
|
free(parsedToBool);
|
||||||
|
}
|
||||||
20
src/parser/not/not.h
Normal file
20
src/parser/not/not.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NOT_H
|
||||||
|
#define NOT_H
|
||||||
|
#include "../parser.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool invert;
|
||||||
|
ParsedValue*value;
|
||||||
|
} ParsedToBool;
|
||||||
|
|
||||||
|
ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index);
|
||||||
|
|
||||||
|
void free_not(void *ptr);
|
||||||
|
|
||||||
|
#endif // NOT_H
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "../../memory.h"
|
#include "../../memory.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
#include <gmp.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -180,7 +179,8 @@ ParsedValueReturn parse_number(Token *token, char *path) {
|
|||||||
mpq_init(*r_ptr);
|
mpq_init(*r_ptr);
|
||||||
int err = mpq_set_decimal_str_exp(*r_ptr, token->value, token->length);
|
int err = mpq_set_decimal_str_exp(*r_ptr, token->value, token->length);
|
||||||
if (err) {
|
if (err) {
|
||||||
free_parsed(parsedValue);
|
mpq_clear(*r_ptr);
|
||||||
|
free(r_ptr);
|
||||||
free(parsedValue);
|
free(parsedValue);
|
||||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
token->length, path, "Parsing Error",
|
token->length, path, "Parsing Error",
|
||||||
@@ -190,3 +190,4 @@ ParsedValueReturn parse_number(Token *token, char *path) {
|
|||||||
parsedValue->data = r_ptr;
|
parsedValue->data = r_ptr;
|
||||||
return (ParsedValueReturn){no_err, parsedValue};
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
#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));
|
||||||
@@ -31,7 +29,9 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
|
|||||||
operation = *current_operation;
|
operation = *current_operation;
|
||||||
darray_init(&positions, sizeof(size_t));
|
darray_init(&positions, sizeof(size_t));
|
||||||
}
|
}
|
||||||
darray_push(&positions, &i);
|
if (operation_type == current_operation->type) {
|
||||||
|
darray_push(&positions, &i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ParsedValue parsedValue;
|
ParsedValue parsedValue;
|
||||||
parsedValue.type = AST_OPERATION;
|
parsedValue.type = AST_OPERATION;
|
||||||
@@ -42,24 +42,22 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
|
|||||||
operationStruct->column = operation.column;
|
operationStruct->column = operation.column;
|
||||||
operationStruct->length = operation.length;
|
operationStruct->length = operation.length;
|
||||||
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
|
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
|
||||||
size_t last_position = 0;
|
|
||||||
size_t to_operate_on_last_position = 0;
|
size_t to_operate_on_last_position = 0;
|
||||||
for (size_t i = 0; i < positions.size; i++) {
|
for (size_t i = 0; i < positions.size; i++) {
|
||||||
size_t *position = darray_get(&positions, i);
|
size_t *position = darray_get(&positions, i);
|
||||||
DArray to_operate_on_slice = darray_slice(
|
DArray to_operate_on_slice = darray_slice(
|
||||||
to_operate_on, to_operate_on_last_position, (*position) + 1);
|
to_operate_on, to_operate_on_last_position, (*position) + 1);
|
||||||
DArray operations_slice =
|
DArray operations_slice =
|
||||||
darray_slice(operations, last_position, *position);
|
darray_slice(operations, to_operate_on_last_position, (*position));
|
||||||
ParsedValue result =
|
ParsedValue result =
|
||||||
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
||||||
darray_push(&operationStruct->to_operate_on, &result);
|
darray_push(&operationStruct->to_operate_on, &result);
|
||||||
last_position = (*position);
|
|
||||||
to_operate_on_last_position = (*position) + 1;
|
to_operate_on_last_position = (*position) + 1;
|
||||||
}
|
}
|
||||||
DArray to_operate_on_slice = darray_slice(
|
DArray to_operate_on_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 operations_slice =
|
||||||
darray_slice(operations, last_position, operations->size);
|
darray_slice(operations, to_operate_on_last_position, operations->size);
|
||||||
ParsedValue result =
|
ParsedValue result =
|
||||||
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
||||||
darray_push(&operationStruct->to_operate_on, &result);
|
darray_push(&operationStruct->to_operate_on, &result);
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parentheses-and-anonymous-function.h"
|
||||||
|
#include "../../memory.h"
|
||||||
|
#include "../assignable/identifier/identifier.h"
|
||||||
|
#include "../function/function.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index) {
|
||||||
|
(*index)++;
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
// darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
DArray list;
|
||||||
|
darray_init(&list, sizeof(ParsedValue));
|
||||||
|
Token *token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_RPAREN) {
|
||||||
|
while (*index < tokens->size) {
|
||||||
|
ParsedValueReturn parsedItem = parse_token(file, tokens, index, true);
|
||||||
|
if (parsedItem.err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return parsedItem;
|
||||||
|
}
|
||||||
|
darray_push(&list, parsedItem.value);
|
||||||
|
free(parsedItem.value);
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type == TOKEN_RPAREN) {
|
||||||
|
break;
|
||||||
|
} else if (token->type != TOKEN_COMMA) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file,
|
||||||
|
"Syntax Error", "expected comma"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*index)++;
|
||||||
|
if (*index < tokens->size) {
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type == TOKEN_ASSIGN) {
|
||||||
|
(*index)++;
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
DArray parameters;
|
||||||
|
darray_init(¶meters, sizeof(char *));
|
||||||
|
for (size_t i = 0; i < list.size; i++) {
|
||||||
|
ParsedValue *item = darray_get(&list, i);
|
||||||
|
if (item->type != AST_IDENTIFIER) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
darray_free(¶meters, free_parameter);
|
||||||
|
return (ParsedValueReturn){
|
||||||
|
create_err(token->line, token->column, token->length, file,
|
||||||
|
"Syntax Error", "expected identifier"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
char *param = strdup(((ParsedIdentifier *)item->data)->name);
|
||||||
|
darray_push(¶meters, ¶m);
|
||||||
|
}
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
ParsedValueReturn parsedBody = parse_token(file, tokens, index, true);
|
||||||
|
if (parsedBody.err.exists) {
|
||||||
|
darray_free(¶meters, free_parameter);
|
||||||
|
return parsedBody;
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){
|
||||||
|
no_err,
|
||||||
|
create_parsed_function("anonymous", parameters, parsedBody.value)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (list.size != 1) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected 1 body"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
memcpy(parsedValue, darray_get(&list, 0), sizeof(ParsedValue));
|
||||||
|
darray_free(&list, NULL);
|
||||||
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef parentheses_and_anonymous_function_H
|
||||||
|
#define parentheses_and_anonymous_function_H
|
||||||
|
#include "../parser.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
|
||||||
|
ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index);
|
||||||
|
|
||||||
|
#endif // parentheses_and_anonymous_function_H
|
||||||
@@ -20,8 +20,11 @@
|
|||||||
#include "literals/literals.h"
|
#include "literals/literals.h"
|
||||||
#include "number/number.h"
|
#include "number/number.h"
|
||||||
#include "operations/operations.h"
|
#include "operations/operations.h"
|
||||||
|
#include "parentheses-and-anonymous-function/parentheses-and-anonymous-function.h"
|
||||||
#include "return/return.h"
|
#include "return/return.h"
|
||||||
#include "string/string.h"
|
#include "string/string.h"
|
||||||
|
#include "not/not.h"
|
||||||
|
#include "while/while.h"
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -30,10 +33,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const char *ValueTypeNames[] = {
|
const char *ValueTypeNames[] = {
|
||||||
"string", "assign", "identifier", "number",
|
"string", "assign", "identifier", "number", "if statement",
|
||||||
"if statement", "access", "call", "declaration",
|
"access", "call", "declaration", "null", "boolean",
|
||||||
"null", "boolean", "do wrap", "operations",
|
"do wrap", "operations", "list", "dictionary", "function",
|
||||||
"list", "dictionary", "function", "return"};
|
"return", "while loop", "not"};
|
||||||
|
|
||||||
ArErr 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) {
|
||||||
@@ -72,6 +75,8 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
|
|||||||
switch (token->type) {
|
switch (token->type) {
|
||||||
case TOKEN_IF:
|
case TOKEN_IF:
|
||||||
return parse_if(file, tokens, index);
|
return parse_if(file, tokens, index);
|
||||||
|
case TOKEN_WHILE:
|
||||||
|
return parse_while(file, tokens, index);
|
||||||
case TOKEN_RETURN:
|
case TOKEN_RETURN:
|
||||||
return parse_return(file, tokens, index);
|
return parse_return(file, tokens, index);
|
||||||
case TOKEN_LET:
|
case TOKEN_LET:
|
||||||
@@ -128,9 +133,15 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
|
|||||||
case TOKEN_LBRACKET:
|
case TOKEN_LBRACKET:
|
||||||
output = parse_list(file, tokens, index);
|
output = parse_list(file, tokens, index);
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_LPAREN:
|
||||||
|
output = parse_parentheses(file, tokens, index);
|
||||||
|
break;
|
||||||
case TOKEN_LBRACE:
|
case TOKEN_LBRACE:
|
||||||
output = parse_dictionary(file, tokens, index);
|
output = parse_dictionary(file, tokens, index);
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_EXCLAMATION:
|
||||||
|
output = parse_not(file, tokens, index);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
token->length, file, "Syntax Error",
|
token->length, file, "Syntax Error",
|
||||||
@@ -147,13 +158,6 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
|
|||||||
token = darray_get(tokens, *index);
|
token = darray_get(tokens, *index);
|
||||||
switch (token->type) {
|
switch (token->type) {
|
||||||
case TOKEN_ASSIGN:
|
case TOKEN_ASSIGN:
|
||||||
case TOKEN_ASSIGN_CARET:
|
|
||||||
case TOKEN_ASSIGN_FLOORDIV:
|
|
||||||
case TOKEN_ASSIGN_MINUS:
|
|
||||||
case TOKEN_ASSIGN_MODULO:
|
|
||||||
case TOKEN_ASSIGN_PLUS:
|
|
||||||
case TOKEN_ASSIGN_SLASH:
|
|
||||||
case TOKEN_ASSIGN_STAR:
|
|
||||||
output = parse_assign(file, tokens, output.value, index);
|
output = parse_assign(file, tokens, output.value, index);
|
||||||
break;
|
break;
|
||||||
case TOKEN_LPAREN:
|
case TOKEN_LPAREN:
|
||||||
@@ -243,6 +247,9 @@ void free_parsed(void *ptr) {
|
|||||||
case AST_IF:
|
case AST_IF:
|
||||||
free_parsed_if(parsed);
|
free_parsed_if(parsed);
|
||||||
break;
|
break;
|
||||||
|
case AST_WHILE:
|
||||||
|
free_parsed_while(parsed);
|
||||||
|
break;
|
||||||
case AST_OPERATION:
|
case AST_OPERATION:
|
||||||
free_operation(parsed);
|
free_operation(parsed);
|
||||||
break;
|
break;
|
||||||
@@ -261,5 +268,8 @@ void free_parsed(void *ptr) {
|
|||||||
case AST_RETURN:
|
case AST_RETURN:
|
||||||
free_parsed_return(parsed);
|
free_parsed_return(parsed);
|
||||||
break;
|
break;
|
||||||
|
case AST_TO_BOOL:
|
||||||
|
free_not(parsed);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,9 @@ typedef enum {
|
|||||||
AST_LIST,
|
AST_LIST,
|
||||||
AST_DICTIONARY,
|
AST_DICTIONARY,
|
||||||
AST_FUNCTION,
|
AST_FUNCTION,
|
||||||
AST_RETURN
|
AST_RETURN,
|
||||||
|
AST_WHILE,
|
||||||
|
AST_TO_BOOL
|
||||||
} ValueType;
|
} ValueType;
|
||||||
|
|
||||||
extern const char *ValueTypeNames[];
|
extern const char *ValueTypeNames[];
|
||||||
|
|||||||
101
src/parser/while/while.c
Normal file
101
src/parser/while/while.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
#include "while.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
#include "../../memory.h"
|
||||||
|
#include "../parser.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
ParsedValueReturn parse_while(char *file, DArray *tokens, size_t *index) {
|
||||||
|
Token *token = darray_get(tokens, *index);
|
||||||
|
(*index)++;
|
||||||
|
// Parse ( condition )
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_LPAREN) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected '(' after while"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
(*index)++;
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
ParsedValueReturn condition = parse_token(file, tokens, index, true);
|
||||||
|
if (condition.err.exists) {
|
||||||
|
return condition;
|
||||||
|
} else if (!condition.value) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected condition"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_RPAREN) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"missing closing ')' in condition"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
(*index)++;
|
||||||
|
err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
// Parse the body
|
||||||
|
ParsedValueReturn parsed_content = parse_token(file, tokens, index, false);
|
||||||
|
|
||||||
|
if (parsed_content.err.exists) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return parsed_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed_content.value) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected body"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedValue *Parsedvalue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
Parsedvalue->type = AST_WHILE;
|
||||||
|
ParsedWhile *Parsed_while = checked_malloc(sizeof(ParsedWhile));
|
||||||
|
Parsedvalue->data = Parsed_while;
|
||||||
|
Parsed_while->condition = condition.value;
|
||||||
|
Parsed_while->content = parsed_content.value;
|
||||||
|
return (ParsedValueReturn){no_err, Parsedvalue};
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_parsed_while(void *ptr) {
|
||||||
|
ParsedValue *parsedValue = ptr;
|
||||||
|
ParsedWhile *parsed_while = parsedValue->data;
|
||||||
|
free_parsed(parsed_while->condition);
|
||||||
|
free(parsed_while->condition);
|
||||||
|
free_parsed(parsed_while->content);
|
||||||
|
free(parsed_while->content);
|
||||||
|
free(parsed_while);
|
||||||
|
}
|
||||||
20
src/parser/while/while.h
Normal file
20
src/parser/while/while.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PARSE_WHILE_H
|
||||||
|
#define PARSE_WHILE_H
|
||||||
|
#include "../parser.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ParsedValue * condition;
|
||||||
|
ParsedValue *content;
|
||||||
|
} ParsedWhile;
|
||||||
|
|
||||||
|
ParsedValueReturn parse_while(char *file, DArray *tokens, size_t *index);
|
||||||
|
|
||||||
|
void free_parsed_while(void *ptr);
|
||||||
|
|
||||||
|
#endif // PARSE_WHILE_H
|
||||||
@@ -8,21 +8,16 @@
|
|||||||
#define RETURN_TYPES_H
|
#define RETURN_TYPES_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "arobject.h"
|
#include "arobject.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define ERR_MSG_MAX_LEN 256
|
|
||||||
|
|
||||||
typedef struct ArErr {
|
typedef struct ArErr {
|
||||||
bool exists;
|
char path[FILENAME_MAX];
|
||||||
char *path;
|
char message[128];
|
||||||
|
char type[64];
|
||||||
int64_t line;
|
int64_t line;
|
||||||
int64_t column;
|
int64_t column;
|
||||||
int length;
|
int length;
|
||||||
char type[32];
|
bool exists;
|
||||||
char message[ERR_MSG_MAX_LEN];
|
|
||||||
} ArErr;
|
} ArErr;
|
||||||
|
|
||||||
typedef struct Execution {
|
|
||||||
ArErr err;
|
|
||||||
Stack stack;
|
|
||||||
} Execution;
|
|
||||||
#endif // RETURN_TYPES_
|
#endif // RETURN_TYPES_
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
29
src/runtime/assignment/assignment.c
Normal file
29
src/runtime/assignment/assignment.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assignment.h"
|
||||||
|
|
||||||
|
void runtime_assignment(Translated *translated, RuntimeState *state,
|
||||||
|
struct Stack *stack) {
|
||||||
|
int64_t length = pop_bytecode(translated, state);
|
||||||
|
int64_t offset = pop_bytecode(translated, state);
|
||||||
|
int64_t prehash = pop_bytecode(translated, state);
|
||||||
|
int64_t from_register = pop_byte(translated, state);
|
||||||
|
void *data = arena_get(&translated->constants, offset);
|
||||||
|
uint64_t hash = runtime_hash(data, length, prehash);
|
||||||
|
ArgonObject *key = new_string_object(data, length, prehash, hash);
|
||||||
|
for (Stack *current_stack = stack; current_stack;
|
||||||
|
current_stack = current_stack->prev) {
|
||||||
|
ArgonObject *exists = hashmap_lookup_GC(current_stack->scope, hash);
|
||||||
|
if (exists) {
|
||||||
|
hashmap_insert_GC(current_stack->scope, hash, key,
|
||||||
|
state->registers[from_register], 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register],
|
||||||
|
0);
|
||||||
|
}
|
||||||
15
src/runtime/assignment/assignment.h
Normal file
15
src/runtime/assignment/assignment.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef runtime_assignment_H
|
||||||
|
#define runtime_assignment_H
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include "../objects/string/string.h"
|
||||||
|
|
||||||
|
void runtime_assignment(Translated *translated, RuntimeState *state,
|
||||||
|
struct Stack *stack);
|
||||||
|
|
||||||
|
#endif // runtime_assignment_H
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0602
|
||||||
|
#endif
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -72,27 +75,26 @@ double get_memory_usage_mb() {
|
|||||||
|
|
||||||
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
|
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
|
||||||
ArgonObject **argv, ArErr *err, RuntimeState *state) {
|
ArgonObject **argv, ArErr *err, RuntimeState *state) {
|
||||||
*err = run_call(original_object, argc, argv, state, true);
|
run_call(original_object, argc, argv, state, true, err);
|
||||||
return state->registers[0];
|
return state->registers[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
||||||
RuntimeState *state, bool CStackFrame) {
|
RuntimeState *state, bool CStackFrame, ArErr *err) {
|
||||||
ArgonObject *object = original_object;
|
ArgonObject *object = original_object;
|
||||||
if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION &&
|
if (object->type != TYPE_FUNCTION && object->type != TYPE_NATIVE_FUNCTION &&
|
||||||
object->type != TYPE_METHOD) {
|
object->type != TYPE_METHOD) {
|
||||||
ArgonObject *call_method =
|
ArgonObject *call_method = get_builtin_field_for_class(
|
||||||
get_field_for_class(get_field(object, "__class__", false, false),
|
get_builtin_field(object, __class__), __call__, original_object);
|
||||||
"__call__", original_object);
|
|
||||||
if (call_method) {
|
if (call_method) {
|
||||||
object = call_method;
|
object = call_method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (object->type == TYPE_METHOD) {
|
if (object->type == TYPE_METHOD) {
|
||||||
ArgonObject *binding_object =
|
ArgonObject *binding_object = get_builtin_field(object, __binding__);
|
||||||
get_field(object, "__binding__", false, false);
|
|
||||||
if (binding_object) {
|
if (binding_object) {
|
||||||
ArgonObject **new_call_args = ar_alloc(sizeof(ArgonObject *) * (argc + 1));
|
ArgonObject **new_call_args =
|
||||||
|
ar_alloc(sizeof(ArgonObject *) * (argc + 1));
|
||||||
new_call_args[0] = binding_object;
|
new_call_args[0] = binding_object;
|
||||||
if (argc > 0) {
|
if (argc > 0) {
|
||||||
memcpy(new_call_args + 1, argv, argc * sizeof(ArgonObject *));
|
memcpy(new_call_args + 1, argv, argc * sizeof(ArgonObject *));
|
||||||
@@ -100,46 +102,48 @@ ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
|||||||
argv = new_call_args;
|
argv = new_call_args;
|
||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
ArgonObject *function_object =
|
ArgonObject *function_object = get_builtin_field(object, __function__);
|
||||||
get_field(object, "__function__", false, false);
|
|
||||||
if (function_object)
|
if (function_object)
|
||||||
object = function_object;
|
object = function_object;
|
||||||
}
|
}
|
||||||
if (object->type == TYPE_FUNCTION) {
|
if (object->type == TYPE_FUNCTION) {
|
||||||
if (argc != object->value.argon_fn.number_of_parameters) {
|
if (argc != object->value.argon_fn->number_of_parameters) {
|
||||||
ArgonObject *type_object_name =
|
ArgonObject *type_object_name = get_builtin_field_for_class(
|
||||||
get_field_for_class(get_field(object, "__class__", false, false),
|
get_builtin_field(object, __class__), __name__, original_object);
|
||||||
"__name__", original_object);
|
|
||||||
ArgonObject *object_name =
|
ArgonObject *object_name =
|
||||||
get_field_for_class(object, "__name__", original_object);
|
get_builtin_field_for_class(object, __name__, original_object);
|
||||||
return create_err(
|
*err = create_err(
|
||||||
state->source_location.line, state->source_location.column,
|
state->source_location.line, state->source_location.column,
|
||||||
state->source_location.length, state->path, "Type Error",
|
state->source_location.length, state->path, "Type Error",
|
||||||
"%.*s %.*s takes %" PRIu64 " argument(s) but %" PRIu64 " was given",
|
"%.*s %.*s takes %" PRIu64 " argument(s) but %" PRIu64 " was given",
|
||||||
(int)type_object_name->value.as_str.length,
|
(int)type_object_name->value.as_str->length,
|
||||||
type_object_name->value.as_str.data,
|
type_object_name->value.as_str->data,
|
||||||
(int)object_name->value.as_str.length, object_name->value.as_str.data,
|
(int)object_name->value.as_str->length,
|
||||||
object->value.argon_fn.number_of_parameters, argc);
|
object_name->value.as_str->data,
|
||||||
|
object->value.argon_fn->number_of_parameters, argc);
|
||||||
}
|
}
|
||||||
Stack *scope = create_scope(object->value.argon_fn.stack);
|
Stack *scope = create_scope(object->value.argon_fn->stack, true);
|
||||||
for (size_t i = 0; i < argc; i++) {
|
for (size_t i = 0; i < argc; i++) {
|
||||||
struct string_struct key = object->value.argon_fn.parameters[i];
|
struct string_struct key = object->value.argon_fn->parameters[i];
|
||||||
ArgonObject *value = argv[i];
|
ArgonObject *value = argv[i];
|
||||||
uint64_t hash = siphash64_bytes(key.data, key.length, siphash_key);
|
uint64_t hash = siphash64_bytes(key.data, key.length, siphash_key);
|
||||||
hashmap_insert_GC(scope->scope, hash,
|
hashmap_insert_GC(scope->scope, hash,
|
||||||
new_string_object(key.data, key.length), value, 0);
|
new_string_object(key.data, key.length, 0, hash), value,
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
StackFrame new_stackFrame = {
|
StackFrame new_stackFrame = {
|
||||||
{object->value.argon_fn.translated.registerCount,
|
{object->value.argon_fn->translated.registerCount,
|
||||||
|
object->value.argon_fn->translated.registerAssignment,
|
||||||
NULL,
|
NULL,
|
||||||
{object->value.argon_fn.bytecode, sizeof(uint8_t),
|
{object->value.argon_fn->bytecode, sizeof(uint8_t),
|
||||||
object->value.argon_fn.bytecode_length,
|
object->value.argon_fn->bytecode_length,
|
||||||
object->value.argon_fn.bytecode_length, false},
|
object->value.argon_fn->bytecode_length, false},
|
||||||
object->value.argon_fn.translated.constants,
|
object->value.argon_fn->translated.constants,
|
||||||
object->value.argon_fn.translated.path},
|
object->value.argon_fn->translated.path},
|
||||||
{state->registers,
|
{ar_alloc(object->value.argon_fn->translated.registerCount *
|
||||||
|
sizeof(ArgonObject *)),
|
||||||
0,
|
0,
|
||||||
object->value.argon_fn.translated.path,
|
object->value.argon_fn->translated.path,
|
||||||
NULL,
|
NULL,
|
||||||
state->currentStackFramePointer,
|
state->currentStackFramePointer,
|
||||||
{},
|
{},
|
||||||
@@ -147,17 +151,17 @@ ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
|||||||
scope,
|
scope,
|
||||||
*state->currentStackFramePointer,
|
*state->currentStackFramePointer,
|
||||||
(*state->currentStackFramePointer)->depth + 1};
|
(*state->currentStackFramePointer)->depth + 1};
|
||||||
|
for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
|
||||||
|
new_stackFrame.state.registers[i] = NULL;
|
||||||
|
}
|
||||||
if (CStackFrame) {
|
if (CStackFrame) {
|
||||||
return runtime(new_stackFrame.translated, new_stackFrame.state, new_stackFrame.stack);
|
runtime(new_stackFrame.translated, new_stackFrame.state,
|
||||||
|
new_stackFrame.stack, err);
|
||||||
|
state->registers[0] = new_stackFrame.state.registers[0];
|
||||||
} else {
|
} else {
|
||||||
if (((*state->currentStackFramePointer)->depth + 1) % STACKFRAME_CHUNKS ==
|
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
|
||||||
0) {
|
*currentStackFrame = new_stackFrame;
|
||||||
*state->currentStackFramePointer =
|
*state->currentStackFramePointer = currentStackFrame;
|
||||||
ar_alloc(sizeof(StackFrame) * STACKFRAME_CHUNKS);
|
|
||||||
} else {
|
|
||||||
*state->currentStackFramePointer = *state->currentStackFramePointer + 1;
|
|
||||||
}
|
|
||||||
**state->currentStackFramePointer = new_stackFrame;
|
|
||||||
if ((*state->currentStackFramePointer)->depth >= 10000) {
|
if ((*state->currentStackFramePointer)->depth >= 10000) {
|
||||||
double logval =
|
double logval =
|
||||||
log10((double)(*state->currentStackFramePointer)->depth);
|
log10((double)(*state->currentStackFramePointer)->depth);
|
||||||
@@ -176,25 +180,23 @@ ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return no_err;
|
return;
|
||||||
}
|
}
|
||||||
} else if (object->type == TYPE_NATIVE_FUNCTION) {
|
} else if (object->type == TYPE_NATIVE_FUNCTION) {
|
||||||
ArErr err = no_err;
|
state->registers[0] = object->value.native_fn(argc, argv, err, state);
|
||||||
state->registers[0] = object->value.native_fn(argc, argv, &err, state);
|
if (err->exists && strlen(err->path) == 0) {
|
||||||
if (err.exists && strlen(err.path) == 0) {
|
err->line = state->source_location.line;
|
||||||
err.line = state->source_location.line;
|
err->column = state->source_location.column;
|
||||||
err.column = state->source_location.column;
|
err->length = state->source_location.length;
|
||||||
err.length = state->source_location.length;
|
strcpy(err->path, state->path);
|
||||||
err.path = state->path;
|
|
||||||
}
|
}
|
||||||
return err;
|
return;
|
||||||
}
|
}
|
||||||
ArgonObject *type_object_name =
|
ArgonObject *type_object_name = get_builtin_field_for_class(
|
||||||
get_field_for_class(get_field(original_object, "__class__", false, false),
|
get_builtin_field(original_object, __class__), __name__, original_object);
|
||||||
"__name__", original_object);
|
*err = create_err(state->source_location.line, state->source_location.column,
|
||||||
return create_err(state->source_location.line, state->source_location.column,
|
|
||||||
state->source_location.length, state->path, "Type Error",
|
state->source_location.length, state->path, "Type Error",
|
||||||
"'%.*s' object is not callable",
|
"'%.*s' object is not callable",
|
||||||
(int)type_object_name->value.as_str.length,
|
(int)type_object_name->value.as_str->length,
|
||||||
type_object_name->value.as_str.data);
|
type_object_name->value.as_str->data);
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
|
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
|
||||||
ArgonObject **argv, ArErr *err, RuntimeState *state);
|
ArgonObject **argv, ArErr *err, RuntimeState *state);
|
||||||
|
|
||||||
ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
||||||
RuntimeState *state, bool CStackFrame);
|
RuntimeState *state, bool CStackFrame, ArErr *err);
|
||||||
|
|
||||||
#endif // runtime_call_H
|
#endif // runtime_call_H
|
||||||
@@ -6,18 +6,23 @@
|
|||||||
|
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
|
|
||||||
ArErr runtime_declaration(Translated *translated, RuntimeState *state,
|
void runtime_declaration(Translated *translated, RuntimeState *state,
|
||||||
struct Stack *stack) {
|
struct Stack *stack, ArErr *err) {
|
||||||
int64_t length = pop_bytecode(translated, state);
|
int64_t length = pop_bytecode(translated, state);
|
||||||
int64_t offset = pop_bytecode(translated, state);
|
int64_t offset = pop_bytecode(translated, state);
|
||||||
int64_t prehash = pop_bytecode(translated, state);
|
int64_t prehash = pop_bytecode(translated, state);
|
||||||
int64_t from_register = pop_byte(translated, state);
|
int64_t from_register = pop_byte(translated, state);
|
||||||
uint64_t hash = runtime_hash(arena_get(&translated->constants, offset), length, prehash);
|
void *data = arena_get(&translated->constants, offset);
|
||||||
ArgonObject * exists = hashmap_lookup_GC(stack->scope, hash);
|
uint64_t hash = runtime_hash(data, length, prehash);
|
||||||
|
ArgonObject *exists = hashmap_lookup_GC(stack->scope, hash);
|
||||||
if (exists) {
|
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));
|
*err = create_err(
|
||||||
|
state->source_location.line, state->source_location.column,
|
||||||
|
state->source_location.length, state->path, "Runtime Error",
|
||||||
|
"Identifier '%.*s' has already been declared in the current scope",
|
||||||
|
length, arena_get(&translated->constants, offset));
|
||||||
}
|
}
|
||||||
ArgonObject * key = new_string_object(arena_get(&translated->constants, offset), length);
|
ArgonObject *key = new_string_object(data, length, prehash, hash);
|
||||||
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register], 0);
|
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register],
|
||||||
return no_err;
|
0);
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "../runtime.h"
|
#include "../runtime.h"
|
||||||
#include "../objects/string/string.h"
|
#include "../objects/string/string.h"
|
||||||
|
|
||||||
ArErr runtime_declaration(Translated *translated, RuntimeState *state,
|
void runtime_declaration(Translated *translated, RuntimeState *state,
|
||||||
struct Stack *stack);
|
struct Stack *stack, ArErr *err);
|
||||||
|
|
||||||
#endif // runtime_declaration_H
|
#endif // runtime_declaration_H
|
||||||
@@ -10,23 +10,58 @@
|
|||||||
#include <gc/gc.h>
|
#include <gc/gc.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct hashmap_GC *createHashmap_GC() {
|
struct hashmap_GC *createHashmap_GC() {
|
||||||
size_t size = 8;
|
|
||||||
struct hashmap_GC *t =
|
struct hashmap_GC *t =
|
||||||
(struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
|
(struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
|
||||||
t->size = size;
|
t->size = 0;
|
||||||
t->order = 1;
|
t->order = 1;
|
||||||
t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size);
|
t->list = NULL;
|
||||||
memset(t->list, 0, sizeof(struct node_GC *) * size);
|
t->hashmap_count = 0;
|
||||||
|
t->count = 0;
|
||||||
|
t->inline_count = 0;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
void hashmap_GC_to_array(struct hashmap_GC *t, struct node_GC**array,
|
||||||
|
size_t *array_length) {
|
||||||
|
size_t array_size = 8;
|
||||||
|
*array_length = 0;
|
||||||
|
*array = ar_alloc(array_size * sizeof(struct node_GC));
|
||||||
|
for (size_t i = 0; i < t->inline_count; i++) {
|
||||||
|
if (*array_length >=array_size) {
|
||||||
|
array_size*=2;
|
||||||
|
*array=ar_realloc(*array, array_size * sizeof(struct node_GC));
|
||||||
|
}
|
||||||
|
(*array)[(*array_length)++] = t->inline_values[i];
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < t->size; i++) {
|
||||||
|
if (!t->list[i]) continue;
|
||||||
|
if (*array_length >=array_size) {
|
||||||
|
array_size*=2;
|
||||||
|
*array=ar_realloc(*array, array_size * sizeof(struct node_GC));
|
||||||
|
}
|
||||||
|
(*array)[(*array_length)++] = *t->list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_hashmap_GC(struct hashmap_GC *t) {
|
||||||
|
if (!t->count)
|
||||||
|
return;
|
||||||
|
t->order = 1;
|
||||||
|
t->count = 0;
|
||||||
|
t->inline_count = 0;
|
||||||
|
t->hashmap_count = 0;
|
||||||
|
memset(t->list, 0, sizeof(struct node_GC *) * t->size);
|
||||||
|
}
|
||||||
|
|
||||||
void resize_hashmap_GC(struct hashmap_GC *t) {
|
void resize_hashmap_GC(struct hashmap_GC *t) {
|
||||||
int old_size = t->size;
|
int old_size = t->size;
|
||||||
int new_size = old_size * 2;
|
int new_size = old_size * 2;
|
||||||
|
if (new_size == 0)
|
||||||
|
new_size = 8;
|
||||||
|
|
||||||
struct node_GC **old_list = t->list;
|
struct node_GC **old_list = t->list;
|
||||||
|
|
||||||
@@ -35,8 +70,9 @@ void resize_hashmap_GC(struct hashmap_GC *t) {
|
|||||||
memset(t->list, 0, sizeof(struct node_GC *) * new_size);
|
memset(t->list, 0, sizeof(struct node_GC *) * new_size);
|
||||||
|
|
||||||
t->size = new_size;
|
t->size = new_size;
|
||||||
t->count = 0;
|
if (!old_list)
|
||||||
|
return;
|
||||||
|
t->hashmap_count = 0;
|
||||||
// Rehash old entries into new list
|
// Rehash old entries into new list
|
||||||
for (int i = 0; i < old_size; i++) {
|
for (int i = 0; i < old_size; i++) {
|
||||||
struct node_GC *temp = old_list[i];
|
struct node_GC *temp = old_list[i];
|
||||||
@@ -53,6 +89,17 @@ int hashCode_GC(struct hashmap_GC *t, uint64_t hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
|
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
|
||||||
|
for (size_t i = 0; i < t->inline_count; i++) {
|
||||||
|
if (t->inline_values[i].hash == hash) {
|
||||||
|
size_t length = t->inline_count - i;
|
||||||
|
if (length > 1) {
|
||||||
|
memmove(&t->inline_values[i], &t->inline_values[i + 1],
|
||||||
|
(length - 1) * sizeof(struct node_GC));
|
||||||
|
}
|
||||||
|
t->inline_count--;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
int pos = hashCode_GC(t, hash);
|
int pos = hashCode_GC(t, hash);
|
||||||
struct node_GC *list = t->list[pos];
|
struct node_GC *list = t->list[pos];
|
||||||
struct node_GC *temp = list;
|
struct node_GC *temp = list;
|
||||||
@@ -68,9 +115,6 @@ int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
|
|||||||
prev = temp;
|
prev = temp;
|
||||||
temp = temp->next;
|
temp = temp->next;
|
||||||
}
|
}
|
||||||
list = NULL;
|
|
||||||
prev = NULL;
|
|
||||||
temp = NULL;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +123,22 @@ void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
|
|||||||
if (!order) {
|
if (!order) {
|
||||||
order = t->order++;
|
order = t->order++;
|
||||||
}
|
}
|
||||||
if ((t->count + 1) > t->size * 0.75) {
|
for (size_t i = 0; i < t->inline_count; i++) {
|
||||||
|
if (t->inline_values[i].hash == hash) {
|
||||||
|
t->inline_values[i].val = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!t->list && t->inline_count < INLINE_HASHMAP_ARRAY_SIZE) {
|
||||||
|
t->inline_values[t->inline_count].hash = hash;
|
||||||
|
t->inline_values[t->inline_count].key = key;
|
||||||
|
t->inline_values[t->inline_count].val = val;
|
||||||
|
t->inline_values[t->inline_count].order = order;
|
||||||
|
t->inline_count++;
|
||||||
|
t->count++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((t->hashmap_count + 1) > t->size * 0.75) {
|
||||||
resize_hashmap_GC(t);
|
resize_hashmap_GC(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,10 +163,18 @@ void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
|
|||||||
newNode->order = order;
|
newNode->order = order;
|
||||||
newNode->next = list;
|
newNode->next = list;
|
||||||
t->list[pos] = newNode;
|
t->list[pos] = newNode;
|
||||||
|
t->hashmap_count++;
|
||||||
t->count++;
|
t->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) {
|
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) {
|
||||||
|
size_t stop = t->inline_count;
|
||||||
|
for (size_t i = 0; i < stop; i++) {
|
||||||
|
if (t->inline_values[i].hash == hash)
|
||||||
|
return t->inline_values[i].val;
|
||||||
|
}
|
||||||
|
if (!t->list)
|
||||||
|
return NULL;
|
||||||
int pos = hashCode_GC(t, hash);
|
int pos = hashCode_GC(t, hash);
|
||||||
struct node_GC *list = t->list[pos];
|
struct node_GC *list = t->list[pos];
|
||||||
struct node_GC *temp = list;
|
struct node_GC *temp = list;
|
||||||
|
|||||||
@@ -6,9 +6,12 @@
|
|||||||
|
|
||||||
#ifndef HASHMAP_GC_H
|
#ifndef HASHMAP_GC_H
|
||||||
#define HASHMAP_GC_H
|
#define HASHMAP_GC_H
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define INLINE_HASHMAP_ARRAY_SIZE 3
|
||||||
|
|
||||||
struct node_GC {
|
struct node_GC {
|
||||||
uint64_t hash;
|
uint64_t hash;
|
||||||
void *key;
|
void *key;
|
||||||
@@ -18,19 +21,27 @@ struct node_GC {
|
|||||||
};
|
};
|
||||||
struct hashmap_GC {
|
struct hashmap_GC {
|
||||||
size_t size;
|
size_t size;
|
||||||
|
struct node_GC inline_values[INLINE_HASHMAP_ARRAY_SIZE];
|
||||||
size_t count;
|
size_t count;
|
||||||
|
size_t inline_count;
|
||||||
|
size_t hashmap_count;
|
||||||
size_t order;
|
size_t order;
|
||||||
struct node_GC **list;
|
struct node_GC **list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hashmap_GC *createHashmap_GC();
|
struct hashmap_GC *createHashmap_GC();
|
||||||
|
|
||||||
|
void clear_hashmap_GC(struct hashmap_GC *t);
|
||||||
|
|
||||||
|
void hashmap_GC_to_array(struct hashmap_GC *t, struct node_GC**array,
|
||||||
|
size_t *array_length);
|
||||||
|
|
||||||
int hashCode_GC(struct hashmap_GC *t, uint64_t hash);
|
int hashCode_GC(struct hashmap_GC *t, uint64_t hash);
|
||||||
|
|
||||||
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash);
|
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);
|
||||||
|
|
||||||
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash);
|
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash);
|
||||||
|
|
||||||
|
|||||||
195
src/runtime/objects/dictionary/dictionary.c
Normal file
195
src/runtime/objects/dictionary/dictionary.c
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
#include "dictionary.h"
|
||||||
|
#include "../../call/call.h"
|
||||||
|
#include "../functions/functions.h"
|
||||||
|
#include "../literals/literals.h"
|
||||||
|
#include "../string/string.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
ArgonObject *ARGON_DICTIONARY_TYPE = NULL;
|
||||||
|
|
||||||
|
ArgonObject *create_ARGON_DICTIONARY_TYPE___init__(size_t argc,
|
||||||
|
ArgonObject **argv,
|
||||||
|
ArErr *err,
|
||||||
|
RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 1) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__init__ expects 1 argument, got %" PRIu64, argc);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
ArgonObject *object = argv[0];
|
||||||
|
object->type = TYPE_DICTIONARY;
|
||||||
|
object->value.as_hashmap = createHashmap_GC();
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
|
||||||
|
ArgonObject **argv,
|
||||||
|
ArErr *err,
|
||||||
|
RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 1) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__init__ expects 1 argument, got %" PRIu64, argc);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
ArgonObject *object = argv[0];
|
||||||
|
size_t string_length = 0;
|
||||||
|
char *string = NULL;
|
||||||
|
struct node_GC *keys;
|
||||||
|
size_t keys_length;
|
||||||
|
hashmap_GC_to_array(object->value.as_hashmap, &keys, &keys_length);
|
||||||
|
char *string_obj = "{";
|
||||||
|
size_t length = strlen(string_obj);
|
||||||
|
string = realloc(string, string_length + length);
|
||||||
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
string_length += length;
|
||||||
|
for (size_t i = 0; i < keys_length; i++) {
|
||||||
|
struct node_GC node = keys[i];
|
||||||
|
ArgonObject *key = node.key;
|
||||||
|
ArgonObject *value = node.val;
|
||||||
|
|
||||||
|
ArgonObject *string_convert_method = get_builtin_field_for_class(
|
||||||
|
get_builtin_field(key, __class__), __repr__, key);
|
||||||
|
|
||||||
|
if (string_convert_method) {
|
||||||
|
ArgonObject *string_object =
|
||||||
|
argon_call(string_convert_method, 0, NULL, err, state);
|
||||||
|
string =
|
||||||
|
realloc(string, string_length + string_object->value.as_str->length);
|
||||||
|
memcpy(string + string_length, string_object->value.as_str->data,
|
||||||
|
string_object->value.as_str->length);
|
||||||
|
string_length += string_object->value.as_str->length;
|
||||||
|
} else {
|
||||||
|
char *string_obj = "<object>";
|
||||||
|
size_t length = strlen(string_obj);
|
||||||
|
string = realloc(string, string_length + length);
|
||||||
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
string_length += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_obj = ": ";
|
||||||
|
size_t length = strlen(string_obj);
|
||||||
|
string = realloc(string, string_length + length);
|
||||||
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
string_length += length;
|
||||||
|
|
||||||
|
string_convert_method = get_builtin_field_for_class(
|
||||||
|
get_builtin_field(value, __class__), __repr__, value);
|
||||||
|
|
||||||
|
if (string_convert_method && value != object) {
|
||||||
|
ArgonObject *string_object =
|
||||||
|
argon_call(string_convert_method, 0, NULL, err, state);
|
||||||
|
string =
|
||||||
|
realloc(string, string_length + string_object->value.as_str->length);
|
||||||
|
memcpy(string + string_length, string_object->value.as_str->data,
|
||||||
|
string_object->value.as_str->length);
|
||||||
|
string_length += string_object->value.as_str->length;
|
||||||
|
} else {
|
||||||
|
char *string_obj = "{...}";
|
||||||
|
size_t length = strlen(string_obj);
|
||||||
|
string = realloc(string, string_length + length);
|
||||||
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
string_length += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != keys_length - 1) {
|
||||||
|
char *string_obj = ", ";
|
||||||
|
size_t length = strlen(string_obj);
|
||||||
|
string = realloc(string, string_length + length);
|
||||||
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
string_length += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_obj = "}";
|
||||||
|
length = strlen(string_obj);
|
||||||
|
string = realloc(string, string_length + length);
|
||||||
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
string_length += length;
|
||||||
|
ArgonObject* result = new_string_object(string, string_length, 0, 0);
|
||||||
|
free(string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(size_t argc,
|
||||||
|
ArgonObject **argv,
|
||||||
|
ArErr *err,
|
||||||
|
RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 2) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__get_attr__ expects 2 argument, got %" PRIu64, argc);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
ArgonObject *object = argv[0];
|
||||||
|
ArgonObject *key = argv[1];
|
||||||
|
int64_t hash = hash_object(key, err, state);
|
||||||
|
if (err->exists) {
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
ArgonObject *result = hashmap_lookup_GC(object->value.as_hashmap, hash);
|
||||||
|
if (!result) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "Attribute Error",
|
||||||
|
"Dictionary has no attribute '%.*s'", key->value.as_str->length, key->value.as_str->data);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ArgonObject *create_ARGON_DICTIONARY_TYPE___set_attr__(size_t argc,
|
||||||
|
ArgonObject **argv,
|
||||||
|
ArErr *err,
|
||||||
|
RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 3) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__set_attr__ expects 2 argument, got %" PRIu64, argc);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
ArgonObject *object = argv[0];
|
||||||
|
ArgonObject *key = argv[1];
|
||||||
|
ArgonObject *value = argv[2];
|
||||||
|
int64_t hash = hash_object(key, err, state);
|
||||||
|
if (err->exists) {
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
hashmap_insert_GC(object->value.as_hashmap, hash, key, value, 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_ARGON_DICTIONARY_TYPE() {
|
||||||
|
ARGON_DICTIONARY_TYPE = new_class();
|
||||||
|
add_builtin_field(ARGON_DICTIONARY_TYPE, __name__,
|
||||||
|
new_string_object_null_terminated("dictionary"));
|
||||||
|
add_builtin_field(ARGON_DICTIONARY_TYPE, __init__,
|
||||||
|
create_argon_native_function(
|
||||||
|
"__init__", create_ARGON_DICTIONARY_TYPE___init__));
|
||||||
|
add_builtin_field(
|
||||||
|
ARGON_DICTIONARY_TYPE, __get_attr__,
|
||||||
|
create_argon_native_function("__get_attr__",
|
||||||
|
create_ARGON_DICTIONARY_TYPE___get_attr__));
|
||||||
|
add_builtin_field(
|
||||||
|
ARGON_DICTIONARY_TYPE, __set_attr__,
|
||||||
|
create_argon_native_function("__set_attr__",
|
||||||
|
create_ARGON_DICTIONARY_TYPE___set_attr__));
|
||||||
|
add_builtin_field(ARGON_DICTIONARY_TYPE, __string__,
|
||||||
|
create_argon_native_function(
|
||||||
|
"__string__", create_ARGON_DICTIONARY_TYPE___string__));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *create_dictionary(struct hashmap_GC *hashmap) {
|
||||||
|
ArgonObject *object = new_instance(ARGON_DICTIONARY_TYPE);
|
||||||
|
object->type = TYPE_DICTIONARY;
|
||||||
|
object->value.as_hashmap = hashmap;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
17
src/runtime/objects/dictionary/dictionary.h
Normal file
17
src/runtime/objects/dictionary/dictionary.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DICTIONARY_H
|
||||||
|
#define DICTIONARY_H
|
||||||
|
#include "../object.h"
|
||||||
|
|
||||||
|
extern ArgonObject *ARGON_DICTIONARY_TYPE;
|
||||||
|
|
||||||
|
void create_ARGON_DICTIONARY_TYPE();
|
||||||
|
|
||||||
|
ArgonObject* create_dictionary(struct hashmap_GC*hashmap);
|
||||||
|
|
||||||
|
#endif // DICTIONARY_H
|
||||||
@@ -7,44 +7,48 @@
|
|||||||
#include "../../runtime.h"
|
#include "../../runtime.h"
|
||||||
#include "../object.h"
|
#include "../object.h"
|
||||||
#include "../string/string.h"
|
#include "../string/string.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
ArgonObject *ARGON_FUNCTION_TYPE = NULL;
|
ArgonObject *ARGON_FUNCTION_TYPE = NULL;
|
||||||
|
|
||||||
ArgonObject *create_argon_native_function(char*name, native_fn native_fn) {
|
ArgonObject *create_argon_native_function(char *name, native_fn native_fn) {
|
||||||
ArgonObject *object = new_object();
|
ArgonObject *object = new_instance(ARGON_FUNCTION_TYPE);
|
||||||
add_field(object, "__class__", ARGON_FUNCTION_TYPE);
|
|
||||||
object->type = TYPE_NATIVE_FUNCTION;
|
object->type = TYPE_NATIVE_FUNCTION;
|
||||||
add_field(object, "__name__", new_string_object(name, strlen(name)));
|
add_builtin_field(object, __name__,
|
||||||
|
new_string_object(name, strlen(name), 0, 0));
|
||||||
object->value.native_fn = native_fn;
|
object->value.native_fn = native_fn;
|
||||||
return object;
|
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 = new_object();
|
ArgonObject *object = new_instance(ARGON_FUNCTION_TYPE);
|
||||||
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);
|
||||||
add_field(object, "__name__", new_string_object(arena_get(&translated->constants, offset), length));
|
add_builtin_field(object, __name__,
|
||||||
object->value.argon_fn.translated = *translated;
|
new_string_object(arena_get(&translated->constants, offset),
|
||||||
object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state);
|
length, 0, 0));
|
||||||
object->value.argon_fn.parameters =
|
object->value.argon_fn = ar_alloc(sizeof(struct argon_function_struct));
|
||||||
ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(struct string_struct));
|
object->value.argon_fn->translated = *translated;
|
||||||
for (size_t i = 0; i < object->value.argon_fn.number_of_parameters; i++) {
|
object->value.argon_fn->number_of_parameters = pop_bytecode(translated, state);
|
||||||
|
object->value.argon_fn->parameters =
|
||||||
|
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++) {
|
||||||
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].data = arena_get(&translated->constants, offset);
|
object->value.argon_fn->parameters[i].data =
|
||||||
object->value.argon_fn.parameters[i].length = length;
|
arena_get(&translated->constants, offset);
|
||||||
|
object->value.argon_fn->parameters[i].length = length;
|
||||||
}
|
}
|
||||||
offset = pop_bytecode(translated, state);
|
offset = pop_bytecode(translated, state);
|
||||||
length = pop_bytecode(translated, state);
|
length = pop_bytecode(translated, state);
|
||||||
object->value.argon_fn.bytecode = arena_get(&translated->constants, offset);
|
object->value.argon_fn->bytecode = arena_get(&translated->constants, offset);
|
||||||
object->value.argon_fn.bytecode_length = length;
|
object->value.argon_fn->bytecode_length = length;
|
||||||
object->value.argon_fn.stack = stack;
|
object->value.argon_fn->stack = stack;
|
||||||
state->registers[0]=object;
|
state->registers[0] = object;
|
||||||
}
|
}
|
||||||
@@ -36,8 +36,8 @@ ArgonObject *ARGON_NUMBER_TYPE___new__(size_t argc, ArgonObject **argv,
|
|||||||
ArgonObject *object = argv[1];
|
ArgonObject *object = argv[1];
|
||||||
|
|
||||||
self->type = TYPE_STRING;
|
self->type = TYPE_STRING;
|
||||||
ArgonObject *boolean_convert_method = get_field_for_class(
|
ArgonObject *boolean_convert_method = get_builtin_field_for_class(
|
||||||
get_field(object, "__class__", false, false), "__number__", object);
|
get_builtin_field(object, __class__), __number__, object);
|
||||||
if (boolean_convert_method) {
|
if (boolean_convert_method) {
|
||||||
ArgonObject *boolean_object =
|
ArgonObject *boolean_object =
|
||||||
argon_call(boolean_convert_method, 0, NULL, err, state);
|
argon_call(boolean_convert_method, 0, NULL, err, state);
|
||||||
@@ -45,11 +45,11 @@ ArgonObject *ARGON_NUMBER_TYPE___new__(size_t argc, ArgonObject **argv,
|
|||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
return boolean_object;
|
return boolean_object;
|
||||||
}
|
}
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
get_field(object, "__class__", false, false), "__name__", object);
|
get_builtin_field(object, __class__), __name__, object);
|
||||||
*err = create_err(
|
*err = create_err(
|
||||||
0, 0, 0, "", "Runtime Error", "cannot convert type '%.*s' to number",
|
0, 0, 0, "", "Runtime Error", "cannot convert type '%.*s' to number",
|
||||||
type_name->value.as_str.length, type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +72,7 @@ ArgonObject *ARGON_NUMBER_TYPE___boolean__(size_t argc, ArgonObject **argv,
|
|||||||
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
|
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
return mpq_cmp_si(*argv[0]->value.as_number, 0, 1) == 0 ? ARGON_FALSE
|
return argv[0]->as_bool ? ARGON_FALSE : ARGON_TRUE;
|
||||||
: ARGON_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
||||||
@@ -85,45 +84,251 @@ ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
|||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_builtin_field(argv[1], __class__), __name__, argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__add__ cannot perform addition between a number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__add__ cannot perform addition between a number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_t r;
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
mpq_init(r);
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
mpq_add(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
ArgonObject *result = new_number_object(r);
|
bool gonna_overflow = (a > 0 && b > 0 && a > INT64_MAX - b) ||
|
||||||
mpq_clear(r);
|
(a < 0 && b < 0 && a < INT64_MIN - b);
|
||||||
return result;
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_int64(a + b);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number->is_int64 &&
|
||||||
|
!argv[1]->value.as_number->is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_add(r, *argv[0]->value.as_number->n.mpq,
|
||||||
|
*argv[1]->value.as_number->n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number->n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number->n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number->n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number->n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
"__subtract__ expects 2 arguments, got %" PRIu64, argc);
|
"__subtract__ expects 2 arguments, got %" PRIu64, argc);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_t r;
|
|
||||||
mpq_init(r);
|
|
||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_builtin_field(argv[1], __class__), __name__, argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__subtract__ cannot perform subtraction between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__subtract__ cannot perform subtraction between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_sub(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
|
||||||
ArgonObject *result = new_number_object(r);
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
mpq_clear(r);
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
return result;
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
|
int64_t neg_a = -a;
|
||||||
|
bool gonna_overflow = (neg_a > 0 && b > 0 && b > INT64_MAX - neg_a) ||
|
||||||
|
(neg_a < 0 && b < 0 && b < INT64_MIN - neg_a);
|
||||||
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_int64(a - b);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number->is_int64 &&
|
||||||
|
!argv[1]->value.as_number->is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_sub(r, *argv[0]->value.as_number->n.mpq,
|
||||||
|
*argv[1]->value.as_number->n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number->n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number->n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number->n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number->n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
||||||
|
ArErr *err, RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 2) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__multiply__ expects 2 arguments, got %" PRIu64, argc);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
|
get_builtin_field(argv[1], __class__), __name__, argv[1]);
|
||||||
|
*err = create_err(
|
||||||
|
0, 0, 0, "", "Runtime Error",
|
||||||
|
"__multiply__ cannot perform multiplication between number and %.*s",
|
||||||
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
|
bool gonna_overflow =
|
||||||
|
a > 0 ? (b > 0 ? a > INT64_MAX / b : b < INT64_MIN / a)
|
||||||
|
: (b > 0 ? a < INT64_MIN / b : a != 0 && b < INT64_MAX / a);
|
||||||
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_int64(a * b);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_mul(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number->is_int64 &&
|
||||||
|
!argv[1]->value.as_number->is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_mul(r, *argv[0]->value.as_number->n.mpq,
|
||||||
|
*argv[1]->value.as_number->n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number->n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number->n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number->n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number->n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_mul(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
|
||||||
|
ArErr *err, RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 2) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__division__ expects 2 arguments, got %" PRIu64, argc);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
|
get_builtin_field(argv[1], __class__), __name__, argv[1]);
|
||||||
|
*err = create_err(
|
||||||
|
0, 0, 0, "", "Runtime Error",
|
||||||
|
"__division__ cannot perform division between number and %.*s",
|
||||||
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
|
return ARGON_NULL;
|
||||||
|
}
|
||||||
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
|
if (!b) {
|
||||||
|
*err =
|
||||||
|
create_err(state->source_location.line, state->source_location.column,
|
||||||
|
state->source_location.length, state->path,
|
||||||
|
"Zero Division Error", "division by zero");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return new_number_object_from_num_and_den(a, b);
|
||||||
|
} else if (!argv[0]->value.as_number->is_int64 &&
|
||||||
|
!argv[1]->value.as_number->is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_div(r, *argv[0]->value.as_number->n.mpq,
|
||||||
|
*argv[1]->value.as_number->n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number->n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number->n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number->n.mpq);
|
||||||
|
if (!argv[1]->value.as_number->n.i64) {
|
||||||
|
*err = create_err(state->source_location.line,
|
||||||
|
state->source_location.column,
|
||||||
|
state->source_location.length, state->path,
|
||||||
|
"Zero Division Error", "division by zero");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number->n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_div(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
|
||||||
@@ -135,7 +340,13 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpq_t *num = argv[0]->value.as_number;
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
char buf[32];
|
||||||
|
snprintf(buf, sizeof(buf), "%" PRId64, argv[0]->value.as_number->n.i64);
|
||||||
|
return new_string_object_null_terminated(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpq_t *num = argv[0]->value.as_number->n.mpq;
|
||||||
|
|
||||||
/* If denominator == 1, print numerator as full integer */
|
/* If denominator == 1, print numerator as full integer */
|
||||||
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
|
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
|
||||||
@@ -277,33 +488,60 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define small_ints_min -256
|
||||||
|
#define small_ints_max 256
|
||||||
|
ArgonObject small_ints[small_ints_max - small_ints_min + 1];
|
||||||
|
struct as_number small_ints_as_number[small_ints_max - small_ints_min + 1];
|
||||||
|
|
||||||
|
void init_small_ints() {
|
||||||
|
for (int64_t i = 0; i <= small_ints_max - small_ints_min; i++) {
|
||||||
|
int64_t n = i + small_ints_min;
|
||||||
|
small_ints[i].type = TYPE_NUMBER;
|
||||||
|
small_ints[i].built_in_slot_length = 0;
|
||||||
|
small_ints[i].dict = NULL;
|
||||||
|
small_ints[i].value.as_number = &small_ints_as_number[i];
|
||||||
|
add_builtin_field(&small_ints[i], __class__, ARGON_NUMBER_TYPE);
|
||||||
|
small_ints[i].value.as_number->is_int64 = true;
|
||||||
|
small_ints[i].value.as_number->n.i64 = n;
|
||||||
|
small_ints[i].as_bool = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void create_ARGON_NUMBER_TYPE() {
|
void create_ARGON_NUMBER_TYPE() {
|
||||||
ARGON_NUMBER_TYPE = new_object();
|
ARGON_NUMBER_TYPE = new_class();
|
||||||
add_field(ARGON_NUMBER_TYPE, "__name__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __name__,
|
||||||
new_string_object_null_terminated("number"));
|
new_string_object_null_terminated("number"));
|
||||||
add_field(
|
add_builtin_field(
|
||||||
ARGON_NUMBER_TYPE, "__string__",
|
ARGON_NUMBER_TYPE, __string__,
|
||||||
create_argon_native_function("__string__", ARGON_NUMBER_TYPE___string__));
|
create_argon_native_function("__string__", ARGON_NUMBER_TYPE___string__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__new__",
|
add_builtin_field(
|
||||||
create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__));
|
ARGON_NUMBER_TYPE, __new__,
|
||||||
add_field(
|
create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__));
|
||||||
ARGON_NUMBER_TYPE, "__number__",
|
add_builtin_field(
|
||||||
|
ARGON_NUMBER_TYPE, __number__,
|
||||||
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
|
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__boolean__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __boolean__,
|
||||||
create_argon_native_function("__boolean__",
|
create_argon_native_function(
|
||||||
ARGON_NUMBER_TYPE___boolean__));
|
"__boolean__", ARGON_NUMBER_TYPE___boolean__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__add__",
|
add_builtin_field(
|
||||||
create_argon_native_function("__add__",
|
ARGON_NUMBER_TYPE, __add__,
|
||||||
ARGON_NUMBER_TYPE___add__));
|
create_argon_native_function("__add__", ARGON_NUMBER_TYPE___add__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__subtract__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __subtract__,
|
||||||
create_argon_native_function("__subtract__",
|
create_argon_native_function(
|
||||||
ARGON_NUMBER_TYPE___subtract__));
|
"__subtract__", ARGON_NUMBER_TYPE___subtract__));
|
||||||
|
add_builtin_field(ARGON_NUMBER_TYPE, __multiply__,
|
||||||
|
create_argon_native_function(
|
||||||
|
"__multiply__", ARGON_NUMBER_TYPE___multiply__));
|
||||||
|
add_builtin_field(ARGON_NUMBER_TYPE, __divide__,
|
||||||
|
create_argon_native_function(
|
||||||
|
"__division__", ARGON_NUMBER_TYPE___division__));
|
||||||
|
init_small_ints();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
|
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
|
||||||
z->_mp_alloc = limbs_count;
|
z->_mp_alloc = limbs_count;
|
||||||
z->_mp_size = 0;
|
z->_mp_size = 0;
|
||||||
z->_mp_d = ar_alloc(limbs_count * sizeof(mp_limb_t));
|
z->_mp_d = ar_alloc_atomic(limbs_count * sizeof(mp_limb_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpq_init_gc_managed(mpq_t q, size_t num_limbs, size_t den_limbs) {
|
void mpq_init_gc_managed(mpq_t q, size_t num_limbs, size_t den_limbs) {
|
||||||
@@ -337,40 +575,129 @@ mpq_t *mpq_new_gc_from(const mpq_t src) {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mpq_to_int64(mpq_t q, int64_t *out) {
|
||||||
|
// Check denominator == 1
|
||||||
|
if (mpz_cmp_ui(mpq_denref(q), 1) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get numerator
|
||||||
|
mpz_t num;
|
||||||
|
mpz_init(num);
|
||||||
|
mpz_set(num, mpq_numref(q));
|
||||||
|
|
||||||
|
// Check bounds
|
||||||
|
if (mpz_cmp_si(num, INT64_MIN) < 0 || mpz_cmp_si(num, INT64_MAX) > 0) {
|
||||||
|
mpz_clear(num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = mpz_get_si(num); // safe because we checked range
|
||||||
|
mpz_clear(num);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool double_to_int64(double x, int64_t *out) {
|
||||||
|
if (x < (double)INT64_MIN || x > (double)INT64_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t i = (int64_t)x;
|
||||||
|
if ((double)i == x) { // no fractional part
|
||||||
|
*out = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object(mpq_t number) {
|
ArgonObject *new_number_object(mpq_t number) {
|
||||||
ArgonObject *object = new_object();
|
int64_t i64 = 0;
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
bool is_int64 = mpq_to_int64(number, &i64);
|
||||||
|
if (is_int64 && i64 >= small_ints_min && i64 <= small_ints_max) {
|
||||||
|
return &small_ints[i64 - small_ints_min];
|
||||||
|
}
|
||||||
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(number);
|
object->value.as_number->n.i64 = i64;
|
||||||
|
object->value.as_number->is_int64 = is_int64;
|
||||||
|
if (object->value.as_number->is_int64) {
|
||||||
|
object->as_bool = object->value.as_number->n.i64;
|
||||||
|
} else {
|
||||||
|
object->value.as_number->n.mpq = mpq_new_gc_from(number);
|
||||||
|
object->as_bool = mpq_cmp_si(number, 0, 1) != 0;
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_long(long n, unsigned long d) {
|
ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d) {
|
||||||
ArgonObject *object = new_object();
|
if (d == 1 && n >= small_ints_min && n <= small_ints_max) {
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
return &small_ints[n - small_ints_min];
|
||||||
mpq_t r;
|
}
|
||||||
mpq_init(r);
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
mpq_set_si(r, n, d);
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(r);
|
if (d == 1) {
|
||||||
mpq_clear(r);
|
object->value.as_number->is_int64 = true;
|
||||||
|
object->value.as_number->n.i64 = n;
|
||||||
|
object->as_bool = n;
|
||||||
|
} else {
|
||||||
|
object->value.as_number->is_int64 = false;
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_set_si(r, n, d);
|
||||||
|
object->value.as_number->n.mpq = mpq_new_gc_from(r);
|
||||||
|
object->as_bool = n != 0;
|
||||||
|
mpq_clear(r);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_number_object_from_int64(int64_t i64) {
|
||||||
|
if (i64 >= small_ints_min && i64 <= small_ints_max) {
|
||||||
|
return &small_ints[i64 - small_ints_min];
|
||||||
|
}
|
||||||
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
|
object->type = TYPE_NUMBER;
|
||||||
|
object->value.as_number->is_int64 = true;
|
||||||
|
object->value.as_number->n.i64 = i64;
|
||||||
|
object->as_bool = i64;
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_double(double d) {
|
ArgonObject *new_number_object_from_double(double d) {
|
||||||
ArgonObject *object = new_object();
|
int64_t i64 = 0;
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
bool is_int64 = double_to_int64(d, &i64);
|
||||||
mpq_t r;
|
if (is_int64 && i64 >= small_ints_min && i64 <= small_ints_max) {
|
||||||
mpq_init(r);
|
return &small_ints[i64 - small_ints_min];
|
||||||
mpq_set_d(r, d);
|
}
|
||||||
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(r);
|
object->value.as_number->n.i64 = i64;
|
||||||
mpq_clear(r);
|
object->value.as_number->is_int64 = is_int64;
|
||||||
|
if (object->value.as_number->is_int64) {
|
||||||
|
object->as_bool = object->value.as_number->n.i64;
|
||||||
|
} else {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_set_d(r, d);
|
||||||
|
object->value.as_number->n.mpq = mpq_new_gc_from(r);
|
||||||
|
object->as_bool = d != 0;
|
||||||
|
mpq_clear(r);
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_number(Translated *translated, RuntimeState *state) {
|
void load_number(Translated *translated, RuntimeState *state) {
|
||||||
uint8_t to_register = pop_byte(translated, state);
|
uint8_t to_register = pop_byte(translated, state);
|
||||||
|
uint8_t is_int64 = pop_byte(translated, state);
|
||||||
|
if (is_int64) {
|
||||||
|
state->registers[to_register] =
|
||||||
|
new_number_object_from_int64(pop_bytecode(translated, state));
|
||||||
|
return;
|
||||||
|
}
|
||||||
size_t num_size = pop_bytecode(translated, state);
|
size_t num_size = pop_bytecode(translated, state);
|
||||||
size_t num_pos = pop_bytecode(translated, state);
|
size_t num_pos = pop_bytecode(translated, state);
|
||||||
mpq_t r;
|
mpq_t r;
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ void create_ARGON_NUMBER_TYPE();
|
|||||||
|
|
||||||
ArgonObject *new_number_object(mpq_t number);
|
ArgonObject *new_number_object(mpq_t number);
|
||||||
|
|
||||||
|
bool mpq_to_int64(mpq_t q, int64_t *out);
|
||||||
|
|
||||||
void load_number(Translated *translated, RuntimeState *state);
|
void load_number(Translated *translated, RuntimeState *state);
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_double(double d);
|
ArgonObject *new_number_object_from_double(double d);
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_long(long n, unsigned long d);
|
ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d);
|
||||||
|
|
||||||
|
ArgonObject *new_number_object_from_int64(int64_t i64);
|
||||||
|
|
||||||
#endif // RUNTIME_NUMBER_H
|
#endif // RUNTIME_NUMBER_H
|
||||||
@@ -7,48 +7,159 @@
|
|||||||
#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 "../call/call.h"
|
||||||
#include "type/type.h"
|
#include "type/type.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
int strcmp_len(const char *s1, size_t len, const char *s2) {
|
||||||
|
size_t s2len = strlen(s2); // length of null-terminated string
|
||||||
|
size_t n = (len < s2len) ? len : s2len;
|
||||||
|
|
||||||
|
int cmp = memcmp(s1, s2, n);
|
||||||
|
if (cmp != 0)
|
||||||
|
return cmp;
|
||||||
|
|
||||||
|
// If prefixes match, decide based on length
|
||||||
|
if (len == s2len)
|
||||||
|
return 0;
|
||||||
|
return (len < s2len) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
ArgonObject *BASE_CLASS = NULL;
|
ArgonObject *BASE_CLASS = NULL;
|
||||||
|
|
||||||
|
const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
||||||
|
"__base__",
|
||||||
|
"__class__",
|
||||||
|
"__name__",
|
||||||
|
"", // above is anything that gets stored in built in slots
|
||||||
|
"__add__",
|
||||||
|
"__string__",
|
||||||
|
"__subtract__",
|
||||||
|
"__multiply__",
|
||||||
|
"__divide__",
|
||||||
|
"__new__",
|
||||||
|
"__init__",
|
||||||
|
"__boolean__",
|
||||||
|
"__get_attr__",
|
||||||
|
"__binding__",
|
||||||
|
"__function__",
|
||||||
|
"address",
|
||||||
|
"__call__",
|
||||||
|
"__number__",
|
||||||
|
"length",
|
||||||
|
"__getattribute__",
|
||||||
|
"__set_attr__",
|
||||||
|
"__hash__",
|
||||||
|
"__repr__"};
|
||||||
|
|
||||||
|
uint64_t built_in_field_hashes[BUILT_IN_FIELDS_COUNT];
|
||||||
|
|
||||||
ArgonObject *new_object() {
|
ArgonObject *new_object() {
|
||||||
ArgonObject *object = ar_alloc(sizeof(ArgonObject));
|
ArgonObject *object = ar_alloc(sizeof(ArgonObject));
|
||||||
|
object->built_in_slot_length = 0;
|
||||||
object->type = TYPE_OBJECT;
|
object->type = TYPE_OBJECT;
|
||||||
object->dict = createHashmap_GC();
|
object->dict = NULL;
|
||||||
add_field(object, "__class__", ARGON_TYPE_TYPE);
|
object->as_bool = true;
|
||||||
add_field(object, "__base__", BASE_CLASS);
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_field(ArgonObject *target, char *name, ArgonObject *object) {
|
void init_built_in_field_hashes() {
|
||||||
hashmap_insert_GC(target->dict,
|
for (int i = 0; i < BUILT_IN_FIELDS_COUNT; i++) {
|
||||||
siphash64_bytes(name, strlen(name), siphash_key), name,
|
built_in_field_hashes[i] = siphash64_bytes(
|
||||||
object, 0);
|
built_in_field_names[i], strlen(built_in_field_names[i]), siphash_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t hash_object(ArgonObject *object, ArErr *err, RuntimeState *state) {
|
||||||
|
ArgonObject *hash_function = get_builtin_field_for_class(
|
||||||
|
get_builtin_field(object, __class__), __hash__, object);
|
||||||
|
if (!hash_function) {
|
||||||
|
*err = create_err(err->line, err->column, err->length, err->path,
|
||||||
|
"Hash Error", "objects class has no __hash__ method");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ArgonObject *hash_result = argon_call(hash_function, 0, NULL, err, state);
|
||||||
|
if (hash_result->type != TYPE_NUMBER ||
|
||||||
|
!hash_result->value.as_number->is_int64) {
|
||||||
|
*err =
|
||||||
|
create_err(err->line, err->column, err->length, err->path, "Hash Error",
|
||||||
|
"hash result needs to be a 64 bit integer.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return hash_result->value.as_number->n.i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_class() {
|
||||||
|
ArgonObject *object = new_object();
|
||||||
|
add_builtin_field(object, __class__, ARGON_TYPE_TYPE);
|
||||||
|
add_builtin_field(object, __base__, BASE_CLASS);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_instance(ArgonObject *of) {
|
||||||
|
ArgonObject *object = new_object();
|
||||||
|
add_builtin_field(object, __class__, of);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_builtin_field(ArgonObject *target, built_in_fields field,
|
||||||
|
ArgonObject *object) {
|
||||||
|
for (size_t i = 0; i < target->built_in_slot_length; i++) {
|
||||||
|
if (target->built_in_slot[i].field == field) {
|
||||||
|
target->built_in_slot[i].value = object;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field > BUILT_IN_ARRAY_COUNT) {
|
||||||
|
if (!target->dict)
|
||||||
|
target->dict = createHashmap_GC();
|
||||||
|
hashmap_insert_GC(target->dict, built_in_field_hashes[field],
|
||||||
|
(char *)built_in_field_names[field], object, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target->built_in_slot[target->built_in_slot_length++] =
|
||||||
|
(struct built_in_slot){field, object};
|
||||||
|
// hashmap_insert_GC(target->dict, built_in_field_hashes[field],
|
||||||
|
// (char *)built_in_field_names[field], object, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_field_l(ArgonObject *target, char *name, uint64_t hash, size_t length,
|
||||||
|
ArgonObject *object) {
|
||||||
|
for (size_t i = 0; i < BUILT_IN_ARRAY_COUNT; i++) {
|
||||||
|
if (strcmp_len(name, length, built_in_field_names[i]) == 0) {
|
||||||
|
add_builtin_field(target, i, object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target->dict)
|
||||||
|
target->dict = createHashmap_GC();
|
||||||
|
char *name_copy = ar_alloc(length);
|
||||||
|
memcpy(name_copy, name, length);
|
||||||
|
name_copy[length] = '\0';
|
||||||
|
hashmap_insert_GC(target->dict, hash, name_copy, object, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *bind_object_to_function(ArgonObject *object,
|
ArgonObject *bind_object_to_function(ArgonObject *object,
|
||||||
ArgonObject *function) {
|
ArgonObject *function) {
|
||||||
ArgonObject *bound_method_wrapper = new_object();
|
ArgonObject *bound_method_wrapper = new_object();
|
||||||
bound_method_wrapper->type = TYPE_METHOD;
|
bound_method_wrapper->type = TYPE_METHOD;
|
||||||
add_field(bound_method_wrapper, "__class__", ARGON_METHOD_TYPE);
|
add_builtin_field(bound_method_wrapper, __class__, ARGON_METHOD_TYPE);
|
||||||
add_field(bound_method_wrapper, "__binding__", object);
|
add_builtin_field(bound_method_wrapper, __binding__, object);
|
||||||
add_field(bound_method_wrapper, "__function__", function);
|
add_builtin_field(bound_method_wrapper, __function__, function);
|
||||||
ArgonObject *function_name = get_field(function, "__name__", false, false);
|
ArgonObject *function_name = get_builtin_field(function, __name__);
|
||||||
if (function_name)
|
if (function_name)
|
||||||
add_field(bound_method_wrapper, "__name__", function_name);
|
add_builtin_field(bound_method_wrapper, __name__, function_name);
|
||||||
return bound_method_wrapper;
|
return bound_method_wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
||||||
size_t length, ArgonObject *binding_object) {
|
uint64_t hash, size_t length,
|
||||||
char *field = "__base__";
|
ArgonObject *binding_object) {
|
||||||
size_t field_size = strlen(field);
|
|
||||||
while (target) {
|
while (target) {
|
||||||
ArgonObject *object = get_field_l(target, name, length, false, false);
|
ArgonObject *object = get_field_l(target, name, hash, length, false, false);
|
||||||
if (object) {
|
if (object) {
|
||||||
if ((object->type == TYPE_FUNCTION ||
|
if ((object->type == TYPE_FUNCTION ||
|
||||||
object->type == TYPE_NATIVE_FUNCTION) &&
|
object->type == TYPE_NATIVE_FUNCTION) &&
|
||||||
@@ -57,35 +168,74 @@ ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
|||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
target = get_field_l(target, field, field_size, false, false);
|
target = get_builtin_field(target, __base__);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *get_field_l(ArgonObject *target, char *name, size_t length,
|
ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash,
|
||||||
bool recursive, bool disable_method_wrapper) {
|
size_t length, bool recursive,
|
||||||
if(!target|| !target->dict) return NULL;
|
bool disable_method_wrapper) {
|
||||||
char *field = "__class__";
|
for (size_t i = 0; i < target->built_in_slot_length; i++) {
|
||||||
size_t field_size = strlen(field);
|
if (strcmp_len(name, length, built_in_field_names[i]) == 0) {
|
||||||
ArgonObject *object = hashmap_lookup_GC(
|
return target->built_in_slot[i].value;
|
||||||
target->dict, siphash64_bytes(name, length, siphash_key));
|
}
|
||||||
|
}
|
||||||
|
if (!target->dict)
|
||||||
|
return NULL;
|
||||||
|
ArgonObject *object = hashmap_lookup_GC(target->dict, hash);
|
||||||
if (!recursive || object)
|
if (!recursive || object)
|
||||||
return object;
|
return object;
|
||||||
ArgonObject *binding = target;
|
ArgonObject *binding = target;
|
||||||
if (disable_method_wrapper)
|
if (disable_method_wrapper)
|
||||||
binding = NULL;
|
binding = NULL;
|
||||||
return get_field_for_class_l(
|
return get_field_for_class_l(get_builtin_field(target, __class__), name, hash,
|
||||||
hashmap_lookup_GC(target->dict,
|
length, binding);
|
||||||
siphash64_bytes(field, field_size, siphash_key)),
|
|
||||||
name, length, binding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive,
|
ArgonObject *get_builtin_field_for_class(ArgonObject *target,
|
||||||
bool disable_method_wrapper) {
|
built_in_fields field,
|
||||||
return get_field_l(target, name, strlen(name), recursive,
|
ArgonObject *binding_object) {
|
||||||
disable_method_wrapper);
|
while (target) {
|
||||||
|
ArgonObject *object = get_builtin_field(target, field);
|
||||||
|
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_builtin_field(target, __base__);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
|
inline ArgonObject *get_builtin_field(ArgonObject *target,
|
||||||
ArgonObject *binding_object) {
|
built_in_fields field) {
|
||||||
return get_field_for_class_l(target, name, strlen(name), binding_object);
|
return get_builtin_field_with_recursion_support(target, field, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *
|
||||||
|
get_builtin_field_with_recursion_support(ArgonObject *target,
|
||||||
|
built_in_fields field, bool recursive,
|
||||||
|
bool disable_method_wrapper) {
|
||||||
|
if (!target)
|
||||||
|
return NULL;
|
||||||
|
for (size_t i = 0; i < target->built_in_slot_length; i++) {
|
||||||
|
if (target->built_in_slot[i].field == field) {
|
||||||
|
return target->built_in_slot[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target->dict)
|
||||||
|
return NULL;
|
||||||
|
ArgonObject *object =
|
||||||
|
hashmap_lookup_GC(target->dict, built_in_field_hashes[field]);
|
||||||
|
if (!recursive || object)
|
||||||
|
return object;
|
||||||
|
ArgonObject *binding = target;
|
||||||
|
if (disable_method_wrapper)
|
||||||
|
binding = NULL;
|
||||||
|
return get_builtin_field_for_class(
|
||||||
|
hashmap_lookup_GC(target->dict, built_in_field_hashes[__class__]), field,
|
||||||
|
binding);
|
||||||
}
|
}
|
||||||
@@ -9,27 +9,42 @@
|
|||||||
#include "../internals/hashmap/hashmap.h"
|
#include "../internals/hashmap/hashmap.h"
|
||||||
#include "../runtime.h"
|
#include "../runtime.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
extern ArgonObject *BASE_CLASS;
|
extern ArgonObject *BASE_CLASS;
|
||||||
|
|
||||||
typedef struct ArgonObject ArgonObject;
|
typedef struct ArgonObject ArgonObject;
|
||||||
ArgonObject *new_object();
|
|
||||||
|
|
||||||
void add_field(ArgonObject *target, char *name, ArgonObject *object);
|
ArgonObject *new_class();
|
||||||
|
ArgonObject *new_instance(ArgonObject * of);
|
||||||
|
|
||||||
|
void init_built_in_field_hashes();
|
||||||
|
|
||||||
|
int64_t hash_object(ArgonObject *object, ArErr *err, RuntimeState *state);
|
||||||
|
|
||||||
|
void add_builtin_field(ArgonObject *target, built_in_fields field,
|
||||||
|
ArgonObject *object);
|
||||||
|
|
||||||
|
void add_field_l(ArgonObject *target, char *name, uint64_t hash, size_t length,
|
||||||
|
ArgonObject *object);
|
||||||
|
|
||||||
ArgonObject *bind_object_to_function(ArgonObject *object,
|
ArgonObject *bind_object_to_function(ArgonObject *object,
|
||||||
ArgonObject *function);
|
ArgonObject *function);
|
||||||
|
|
||||||
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
||||||
size_t length, ArgonObject *binding_object);
|
uint64_t hash, size_t length,
|
||||||
|
ArgonObject *binding_object);
|
||||||
|
|
||||||
ArgonObject *get_field_l(ArgonObject *target, char *name, size_t length,
|
ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash,
|
||||||
bool recursive, bool disable_method_wrapper);
|
size_t length, bool recursive,
|
||||||
|
bool disable_method_wrapper);
|
||||||
|
|
||||||
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
|
ArgonObject *get_builtin_field_for_class(ArgonObject *target,
|
||||||
ArgonObject *binding_object);
|
built_in_fields field,
|
||||||
|
ArgonObject *binding_object);
|
||||||
|
|
||||||
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive,
|
ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field);
|
||||||
bool disable_method_wrapper);
|
|
||||||
|
ArgonObject *get_builtin_field_with_recursion_support(ArgonObject *target, built_in_fields field, bool recursive, bool disable_method_wrapper);
|
||||||
|
|
||||||
#endif // OBJECT_H
|
#endif // OBJECT_H
|
||||||
@@ -4,27 +4,85 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../object.h"
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "../number/number.h"
|
#include "../number/number.h"
|
||||||
|
#include "../object.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
ArgonObject *ARGON_STRING_TYPE = NULL;
|
ArgonObject *ARGON_STRING_TYPE = NULL;
|
||||||
|
|
||||||
ArgonObject *new_string_object(char*data, size_t length) {
|
|
||||||
ArgonObject * object = new_object();
|
|
||||||
add_field(object, "__class__", ARGON_STRING_TYPE);
|
|
||||||
add_field(object, "length", new_number_object_from_long(length, 1));
|
char *c_quote_string(const char *input, size_t len) {
|
||||||
|
// Worst case: every byte becomes "\uXXXX" (6 chars) + quotes + NUL
|
||||||
|
size_t max_out = 2 + (len * 6) + 1;
|
||||||
|
char *out = malloc(max_out);
|
||||||
|
if (!out) return NULL;
|
||||||
|
|
||||||
|
size_t j = 0;
|
||||||
|
out[j++] = '"';
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
unsigned char c = (unsigned char)input[i];
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
out[j++] = '\\'; out[j++] = 'n'; break;
|
||||||
|
case '\t':
|
||||||
|
out[j++] = '\\'; out[j++] = 't'; break;
|
||||||
|
case '\r':
|
||||||
|
out[j++] = '\\'; out[j++] = 'r'; break;
|
||||||
|
case '\\':
|
||||||
|
out[j++] = '\\'; out[j++] = '\\'; break;
|
||||||
|
case '\"':
|
||||||
|
out[j++] = '\\'; out[j++] = '\"'; break;
|
||||||
|
default:
|
||||||
|
if (isprint(c)) {
|
||||||
|
out[j++] = c;
|
||||||
|
} else {
|
||||||
|
// write \uXXXX
|
||||||
|
j += sprintf(&out[j], "\\u%04X", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out[j++] = '"';
|
||||||
|
out[j] = '\0';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||||
|
uint64_t hash) {
|
||||||
|
add_builtin_field(object, field_length,
|
||||||
|
new_number_object_from_int64(length));
|
||||||
object->type = TYPE_STRING;
|
object->type = TYPE_STRING;
|
||||||
object->value.as_str.data = ar_alloc_atomic(length);
|
object->value.as_str = ar_alloc(sizeof(struct string_struct));
|
||||||
memcpy(object->value.as_str.data, data, length);
|
object->value.as_str->data = data;
|
||||||
object->value.as_str.length = length;
|
object->value.as_str->prehash = prehash;
|
||||||
|
object->value.as_str->hash_computed = hash;
|
||||||
|
object->value.as_str->hash = hash;
|
||||||
|
object->value.as_str->length = length;
|
||||||
|
object->as_bool = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash,
|
||||||
|
uint64_t hash) {
|
||||||
|
ArgonObject *object = new_instance(ARGON_STRING_TYPE);
|
||||||
|
init_string(object,data,length,prehash,hash);
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_string_object_null_terminated(char*data) {
|
ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash,
|
||||||
return new_string_object(data, strlen(data));
|
uint64_t hash) {
|
||||||
|
char*data_copy = ar_alloc_atomic(length);
|
||||||
|
memcpy(data_copy, data, length);
|
||||||
|
return new_string_object_without_memcpy(data_copy,length, prehash, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_string_object_null_terminated(char *data) {
|
||||||
|
return new_string_object(data, strlen(data), 0, 0);
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,15 @@
|
|||||||
|
|
||||||
extern ArgonObject *ARGON_STRING_TYPE;
|
extern ArgonObject *ARGON_STRING_TYPE;
|
||||||
|
|
||||||
ArgonObject *new_string_object(char*data, size_t length);
|
char *c_quote_string(const char *input, size_t len);
|
||||||
|
|
||||||
|
void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||||
|
uint64_t hash);
|
||||||
|
|
||||||
|
ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash,
|
||||||
|
uint64_t hash);
|
||||||
|
|
||||||
|
ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, uint64_t hash);
|
||||||
|
|
||||||
ArgonObject *new_string_object_null_terminated(char*data);
|
ArgonObject *new_string_object_null_terminated(char*data);
|
||||||
#endif // STRING_OBJ_H
|
#endif // STRING_OBJ_H
|
||||||
@@ -13,14 +13,14 @@ ArgonObject *term_log(size_t argc, ArgonObject **argv, ArErr *err,
|
|||||||
for (size_t i = 0; i < argc; i++) {
|
for (size_t i = 0; i < argc; i++) {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
ArgonObject *string_convert_method = get_field_for_class(
|
ArgonObject *string_convert_method = get_builtin_field_for_class(
|
||||||
get_field(argv[i], "__class__", false, false), "__string__", argv[i]);
|
get_builtin_field(argv[i], __class__), __string__, argv[i]);
|
||||||
|
|
||||||
if (string_convert_method) {
|
if (string_convert_method) {
|
||||||
ArgonObject *string_object =
|
ArgonObject *string_object =
|
||||||
argon_call(string_convert_method, 0, NULL, err, state);
|
argon_call(string_convert_method, 0, NULL, err, state);
|
||||||
fwrite(string_object->value.as_str.data, sizeof(char),
|
fwrite(string_object->value.as_str->data, sizeof(char),
|
||||||
string_object->value.as_str.length, stdout);
|
string_object->value.as_str->length, stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,10 @@
|
|||||||
#include "../translator/translator.h"
|
#include "../translator/translator.h"
|
||||||
#include "internals/dynamic_array_armem/darray_armem.h"
|
#include "internals/dynamic_array_armem/darray_armem.h"
|
||||||
#include "internals/hashmap/hashmap.h"
|
#include "internals/hashmap/hashmap.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
|
||||||
extern ArgonObject *ARGON_METHOD_TYPE;
|
extern ArgonObject *ARGON_METHOD_TYPE;
|
||||||
extern Stack *Global_Scope;
|
extern Stack *Global_Scope;
|
||||||
@@ -54,8 +58,6 @@ typedef struct StackFrame {
|
|||||||
uint64_t depth;
|
uint64_t depth;
|
||||||
} StackFrame;
|
} StackFrame;
|
||||||
|
|
||||||
#define STACKFRAME_CHUNKS 64
|
|
||||||
|
|
||||||
void bootstrap_types();
|
void bootstrap_types();
|
||||||
|
|
||||||
extern struct hashmap *runtime_hash_table;
|
extern struct hashmap *runtime_hash_table;
|
||||||
@@ -64,17 +66,34 @@ uint64_t runtime_hash(const void *data, size_t len, uint64_t prehash);
|
|||||||
|
|
||||||
void bootstrap_globals();
|
void bootstrap_globals();
|
||||||
|
|
||||||
uint8_t pop_byte(Translated *translated, RuntimeState *state);
|
static inline void *arena_get(ConstantArena *arena, size_t offset) {
|
||||||
|
return (char *)arena->data + offset;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t pop_bytecode(Translated *translated, RuntimeState *state);
|
static inline uint8_t pop_byte(Translated *translated, RuntimeState *state) {
|
||||||
|
return *(((uint8_t *)(translated->bytecode.data)) + state->head++);
|
||||||
|
}
|
||||||
|
|
||||||
ArErr run_instruction(Translated *translated, RuntimeState *state,
|
static inline uint64_t pop_bytecode(Translated *translated,
|
||||||
struct Stack **stack);
|
RuntimeState *state) {
|
||||||
|
uint64_t *ptr =
|
||||||
|
(uint64_t *)((uint8_t *)translated->bytecode.data + state->head);
|
||||||
|
state->head += 8;
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void run_instruction(Translated *translated, RuntimeState *state,
|
||||||
|
struct Stack **stack, ArErr *err);
|
||||||
|
|
||||||
RuntimeState init_runtime_state(Translated translated, char *path);
|
RuntimeState init_runtime_state(Translated translated, char *path);
|
||||||
|
|
||||||
Stack *create_scope(Stack *prev);
|
Stack *create_scope(Stack *prev, bool force);
|
||||||
|
|
||||||
ArErr runtime(Translated translated, RuntimeState state, Stack *stack);
|
void add_to_scope(Stack *stack, char *name, ArgonObject *value);
|
||||||
|
|
||||||
|
void add_to_hashmap(struct hashmap_GC *hashmap, char *name, ArgonObject *value);
|
||||||
|
|
||||||
|
void runtime(Translated translated, RuntimeState state, Stack *stack,
|
||||||
|
ArErr *err);
|
||||||
|
|
||||||
#endif // RUNTIME_H
|
#endif // RUNTIME_H
|
||||||
325
src/shell.c
Normal file
325
src/shell.c
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
#include "./lexer/lexer.h"
|
||||||
|
#include "./runtime/call/call.h"
|
||||||
|
#include "./runtime/objects/functions/functions.h"
|
||||||
|
#include "./runtime/objects/term/term.h"
|
||||||
|
#include "./runtime/runtime.h"
|
||||||
|
#include "./translator/translator.h"
|
||||||
|
#include "LICENSE_c.h"
|
||||||
|
#include "import.h"
|
||||||
|
#include "runtime/objects/literals/literals.h"
|
||||||
|
#include "runtime/objects/string/string.h"
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
|
FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
||||||
|
if (strchr(mode, 'r') == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *tmp = tmpfile();
|
||||||
|
if (!tmp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fwrite(buf, 1, size, tmp) != size) {
|
||||||
|
fclose(tmp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewind(tmp);
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only define ssize_t if it doesn't already exist
|
||||||
|
#ifndef _SSIZE_T_DEFINED
|
||||||
|
typedef long ssize_t;
|
||||||
|
#define _SSIZE_T_DEFINED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
|
if (!lineptr || !n || !stream) return -1;
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (*lineptr == NULL || *n == 0) {
|
||||||
|
*n = 128;
|
||||||
|
*lineptr = malloc(*n);
|
||||||
|
if (!*lineptr) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = fgetc(stream)) != EOF) {
|
||||||
|
if (pos + 1 >= *n) {
|
||||||
|
*n *= 2;
|
||||||
|
char *tmp = realloc(*lineptr, *n);
|
||||||
|
if (!tmp) return -1;
|
||||||
|
*lineptr = tmp;
|
||||||
|
}
|
||||||
|
(*lineptr)[pos++] = c;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == 0 && c == EOF)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
(*lineptr)[pos] = '\0';
|
||||||
|
return (ssize_t)pos;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include "../external/linenoise/linenoise.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Ctrl+C handler
|
||||||
|
void handle_sigint(int sig) {
|
||||||
|
(void)sig;
|
||||||
|
printf("\nBye :)\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int execute_code(FILE *stream, char *path, Stack *scope,
|
||||||
|
RuntimeState *runtime_state) {
|
||||||
|
if (!stream) {
|
||||||
|
perror("fmemopen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArErr err = no_err;
|
||||||
|
|
||||||
|
DArray tokens;
|
||||||
|
darray_init(&tokens, sizeof(Token));
|
||||||
|
LexerState state = {path, stream, 0, 0, &tokens};
|
||||||
|
err = lexer(state);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&tokens, free_token);
|
||||||
|
output_err(err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DArray ast;
|
||||||
|
|
||||||
|
darray_init(&ast, sizeof(ParsedValue));
|
||||||
|
|
||||||
|
err = parser(path, &ast, &tokens, false);
|
||||||
|
darray_free(&tokens, free_token);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&ast, free_parsed);
|
||||||
|
output_err(err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Translated __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);
|
||||||
|
output_err(err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashmap_free(__translated.constants.hashmap, NULL);
|
||||||
|
Translated translated = {
|
||||||
|
__translated.registerCount, __translated.registerAssignment, NULL, {}, {},
|
||||||
|
__translated.path};
|
||||||
|
translated.bytecode.data = ar_alloc(__translated.bytecode.capacity);
|
||||||
|
memcpy(translated.bytecode.data, __translated.bytecode.data,
|
||||||
|
__translated.bytecode.capacity);
|
||||||
|
translated.bytecode.element_size = __translated.bytecode.element_size;
|
||||||
|
translated.bytecode.size = __translated.bytecode.size;
|
||||||
|
translated.bytecode.resizable = false;
|
||||||
|
translated.bytecode.capacity =
|
||||||
|
__translated.bytecode.size * __translated.bytecode.element_size;
|
||||||
|
translated.constants.data = ar_alloc(__translated.constants.capacity);
|
||||||
|
memcpy(translated.constants.data, __translated.constants.data,
|
||||||
|
__translated.constants.capacity);
|
||||||
|
translated.constants.size = __translated.constants.size;
|
||||||
|
translated.constants.capacity = __translated.constants.capacity;
|
||||||
|
darray_free(&__translated.bytecode, NULL);
|
||||||
|
free(__translated.constants.data);
|
||||||
|
*runtime_state = init_runtime_state(translated, path);
|
||||||
|
runtime(translated, *runtime_state, scope, &err);
|
||||||
|
if (err.exists) {
|
||||||
|
output_err(err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple input function
|
||||||
|
char *input(const char *prompt) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
printf("%s", prompt);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
char *buffer = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
ssize_t len = getline(&buffer, &size, stdin);
|
||||||
|
|
||||||
|
if (len == -1) {
|
||||||
|
free(buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0 && buffer[len - 1] == '\n') {
|
||||||
|
buffer[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
char *buffer = linenoise(prompt);
|
||||||
|
if (buffer && buffer[0] != '\0') {
|
||||||
|
linenoiseHistoryAdd(buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *read_all_stdin(size_t *out_len) {
|
||||||
|
size_t size = 1024;
|
||||||
|
size_t len = 0;
|
||||||
|
char *buffer = malloc(size);
|
||||||
|
if (!buffer)
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
int c;
|
||||||
|
while ((c = fgetc(stdin)) != EOF) {
|
||||||
|
if (len + 1 >= size) {
|
||||||
|
size *= 2;
|
||||||
|
buffer = realloc(buffer, size);
|
||||||
|
if (!buffer)
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
buffer[len++] = (char)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_len = len;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shell() {
|
||||||
|
|
||||||
|
Stack *main_scope = create_scope(Global_Scope, true);
|
||||||
|
|
||||||
|
if (!isatty(STDIN_FILENO)) {
|
||||||
|
RuntimeState runtime_state;
|
||||||
|
size_t len;
|
||||||
|
char *data = read_all_stdin(&len);
|
||||||
|
FILE *file = fmemopen(data, len, "r");
|
||||||
|
int resp = execute_code(file, "<stdin>", main_scope, &runtime_state);
|
||||||
|
fclose(file);
|
||||||
|
free(data);
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
add_to_scope(main_scope, "license",
|
||||||
|
new_string_object_without_memcpy((char *)LICENSE_txt,
|
||||||
|
LICENSE_txt_len, 0, 0));
|
||||||
|
|
||||||
|
signal(SIGINT, handle_sigint);
|
||||||
|
|
||||||
|
printf("Argon (Chloride %s)\nType \"license\" for more information.\n",
|
||||||
|
version_string);
|
||||||
|
|
||||||
|
ArgonObject *output_object = create_argon_native_function("log", term_log);
|
||||||
|
char *totranslate = NULL;
|
||||||
|
size_t totranslatelength = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
#if defined(__linux__)
|
||||||
|
malloc_trim(0);
|
||||||
|
#endif
|
||||||
|
if (totranslate) {
|
||||||
|
free(totranslate);
|
||||||
|
totranslate = NULL;
|
||||||
|
totranslatelength = 0;
|
||||||
|
};
|
||||||
|
int indent = 0;
|
||||||
|
int last_indent = 0;
|
||||||
|
char textBefore[] = ">>> ";
|
||||||
|
|
||||||
|
// Dynamic array of lines
|
||||||
|
|
||||||
|
do {
|
||||||
|
last_indent = indent;
|
||||||
|
// indent string
|
||||||
|
size_t isz = (size_t)indent * 4;
|
||||||
|
char *indentStr = (char *)malloc(isz + 1);
|
||||||
|
if (!indentStr)
|
||||||
|
exit(1);
|
||||||
|
memset(indentStr, ' ', isz);
|
||||||
|
indentStr[isz] = '\0';
|
||||||
|
|
||||||
|
// prompt
|
||||||
|
size_t p_len = strlen(textBefore) + isz;
|
||||||
|
char *prompt = (char *)malloc(p_len + 1);
|
||||||
|
if (!prompt)
|
||||||
|
exit(1);
|
||||||
|
memcpy(prompt, textBefore, strlen(textBefore));
|
||||||
|
memcpy(prompt + strlen(textBefore), indentStr, isz + 1);
|
||||||
|
|
||||||
|
char *inp = input(prompt);
|
||||||
|
free(prompt);
|
||||||
|
|
||||||
|
if (!inp) {
|
||||||
|
printf("\nBye :)\n");
|
||||||
|
// Free previously collected lines
|
||||||
|
free(inp);
|
||||||
|
free(totranslate);
|
||||||
|
free(indentStr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append line to totranslate
|
||||||
|
size_t length = strlen(inp);
|
||||||
|
totranslate = realloc(totranslate, totranslatelength + isz + length + 1);
|
||||||
|
memcpy(totranslate + totranslatelength, indentStr, isz);
|
||||||
|
memcpy(totranslate + totranslatelength + isz, inp, length);
|
||||||
|
totranslatelength += isz + length + 1;
|
||||||
|
totranslate[totranslatelength - 1] = '\n';
|
||||||
|
|
||||||
|
char *trimmed = inp;
|
||||||
|
while (*trimmed == ' ' || *trimmed == '\t')
|
||||||
|
trimmed++;
|
||||||
|
|
||||||
|
size_t len = strlen(trimmed);
|
||||||
|
if (len >= 2 && strcmp(trimmed + len - 2, "do") == 0) {
|
||||||
|
indent++;
|
||||||
|
} else if (len == 0 && indent > 0) {
|
||||||
|
indent--;
|
||||||
|
}
|
||||||
|
free(inp);
|
||||||
|
strcpy(textBefore, "... ");
|
||||||
|
free(indentStr);
|
||||||
|
|
||||||
|
} while (indent > 0 || last_indent != 0);
|
||||||
|
totranslate = realloc(totranslate, totranslatelength + 1);
|
||||||
|
totranslate[totranslatelength] = '\0';
|
||||||
|
RuntimeState runtime_state;
|
||||||
|
FILE *file = fmemopen((void *)totranslate, totranslatelength, "r");
|
||||||
|
int resp = execute_code(file, "<shell>", main_scope, &runtime_state);
|
||||||
|
fclose(file);
|
||||||
|
if (resp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (runtime_state.registers[0]&&runtime_state.registers[0] != ARGON_NULL) {
|
||||||
|
ArErr err = no_err;
|
||||||
|
argon_call(output_object, 1,
|
||||||
|
(ArgonObject *[]){runtime_state.registers[0]}, &err,
|
||||||
|
&runtime_state);
|
||||||
|
}
|
||||||
|
totranslatelength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
12
src/shell.h
Normal file
12
src/shell.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARGON_SHELL_H
|
||||||
|
#define ARGON_SHELL_H
|
||||||
|
|
||||||
|
int shell();
|
||||||
|
|
||||||
|
#endif // ARGON_SHELL_H
|
||||||
@@ -8,21 +8,19 @@
|
|||||||
size_t translate_access(Translated *translated, ParsedAccess *access,
|
size_t translate_access(Translated *translated, ParsedAccess *access,
|
||||||
ArErr *err) {
|
ArErr *err) {
|
||||||
set_registers(translated, 1);
|
set_registers(translated, 1);
|
||||||
uint64_t first = push_instruction_byte(translated, OP_LOAD_ACCESS_FUNCTION);
|
uint64_t first = translate_parsed(translated, access->to_access, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
push_instruction_byte(translated, OP_LOAD_GETATTRIBUTE_METHOD);
|
||||||
push_instruction_byte(translated, OP_INIT_CALL);
|
push_instruction_byte(translated, OP_INIT_CALL);
|
||||||
push_instruction_code(translated, 3);
|
|
||||||
|
|
||||||
translate_parsed(translated, &access->to_access, err);
|
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
|
||||||
push_instruction_code(translated, 0);
|
|
||||||
translate_parsed(translated, darray_get(&access->access, 0), err);
|
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
|
||||||
push_instruction_code(translated, 1);
|
push_instruction_code(translated, 1);
|
||||||
|
|
||||||
push_instruction_byte(translated, OP_LOAD_BOOL);
|
translate_parsed(translated, access->access, err);
|
||||||
push_instruction_byte(translated, access->access_fields);
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||||
push_instruction_code(translated, 2);
|
push_instruction_code(translated, 0);
|
||||||
|
|
||||||
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
||||||
push_instruction_code(translated, access->line);
|
push_instruction_code(translated, access->line);
|
||||||
push_instruction_code(translated, access->column);
|
push_instruction_code(translated, access->column);
|
||||||
|
|||||||
80
src/translator/assignment/assignment.c
Normal file
80
src/translator/assignment/assignment.c
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assignment.h"
|
||||||
|
#include "../../hash_data/hash_data.h"
|
||||||
|
#include "../../parser/assignable/access/access.h"
|
||||||
|
#include "../../parser/assignable/identifier/identifier.h"
|
||||||
|
#include "../translator.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
size_t translate_parsed_assignment(Translated *translated,
|
||||||
|
ParsedAssign *assignment, ArErr *err) {
|
||||||
|
set_registers(translated, 1);
|
||||||
|
DArray *old_return_jumps = translated->return_jumps;
|
||||||
|
translated->return_jumps = NULL;
|
||||||
|
size_t first = translate_parsed(translated, assignment->from, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
switch (assignment->to->type) {
|
||||||
|
case AST_IDENTIFIER:;
|
||||||
|
ParsedIdentifier *identifier = assignment->to->data;
|
||||||
|
size_t length = strlen(identifier->name);
|
||||||
|
size_t offset =
|
||||||
|
arena_push(&translated->constants, identifier->name, length);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
||||||
|
push_instruction_code(translated, identifier->line);
|
||||||
|
push_instruction_code(translated, identifier->column);
|
||||||
|
push_instruction_code(translated, length);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_ASSIGN);
|
||||||
|
push_instruction_code(translated, length);
|
||||||
|
push_instruction_code(translated, offset);
|
||||||
|
push_instruction_code(translated,
|
||||||
|
siphash64_bytes(identifier->name, length,
|
||||||
|
siphash_key_fixed_for_translator));
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
break;
|
||||||
|
case AST_ACCESS:;
|
||||||
|
ParsedAccess *access = assignment->to->data;
|
||||||
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
|
set_registers(translated, registerA);
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
translate_parsed(translated, access->to_access, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
push_instruction_byte(translated, OP_LOAD_SETATTR_METHOD);
|
||||||
|
push_instruction_byte(translated, OP_INIT_CALL);
|
||||||
|
push_instruction_code(translated, 2);
|
||||||
|
translate_parsed(translated, access->access, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||||
|
push_instruction_code(translated, 0);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||||
|
push_instruction_code(translated, 1);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_CALL);
|
||||||
|
translated->registerAssignment--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "panic: unsupported assignment\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
translated->return_jumps = old_return_jumps;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
15
src/translator/assignment/assignment.h
Normal file
15
src/translator/assignment/assignment.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BYTECODE_ASSIGNMENT_H
|
||||||
|
#define BYTECODE_ASSIGNMENT_H
|
||||||
|
#include "../translator.h"
|
||||||
|
#include "../../parser/assignable/assign/assign.h"
|
||||||
|
|
||||||
|
size_t translate_parsed_assignment(Translated *translated,
|
||||||
|
ParsedAssign *assignment, ArErr *err);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -29,6 +29,17 @@ this operation takes 3 operands.
|
|||||||
1. the fixed hash of the variable name.
|
1. the fixed hash of the variable name.
|
||||||
1. the register of the given value (*)
|
1. the register of the given value (*)
|
||||||
|
|
||||||
|
## OP_ASSIGN
|
||||||
|
|
||||||
|
assigns to a variable in the stack. if the variable doesnt exist on the stack, it is automatically declared on the current scope.
|
||||||
|
|
||||||
|
this operation takes 3 operands.
|
||||||
|
|
||||||
|
1. the length of the variable name.
|
||||||
|
1. the offset in the constant buffer of the variable name.
|
||||||
|
1. the fixed hash of the variable name.
|
||||||
|
1. the register of the given value (*)
|
||||||
|
|
||||||
## OP_LOAD_NULL
|
## OP_LOAD_NULL
|
||||||
|
|
||||||
sets a given register to null.
|
sets a given register to null.
|
||||||
@@ -60,9 +71,7 @@ initilises a function to a given register.
|
|||||||
|
|
||||||
## OP_BOOL
|
## OP_BOOL
|
||||||
|
|
||||||
converts a value in a given register into true or false depending on the result from \_\_bool\_\_
|
converts a value in register 0 into true or false depending on the result from \_\_bool\_\_ (using asBool if the object is a primitive)
|
||||||
|
|
||||||
1. the register to read and write to. (*)
|
|
||||||
|
|
||||||
## OP_JUMP_IF_FALSE
|
## OP_JUMP_IF_FALSE
|
||||||
|
|
||||||
@@ -71,17 +80,20 @@ jumps when a the value in the given register is false.
|
|||||||
1. the register to read. (*)
|
1. the register to read. (*)
|
||||||
1. the index to jump to.
|
1. the index to jump to.
|
||||||
|
|
||||||
## OP_JUMP_IF_FALSE
|
## OP_JUMP
|
||||||
|
|
||||||
jumps unconditionally to an index.
|
jumps unconditionally to an index.
|
||||||
|
|
||||||
1. the index to jump to.
|
1. the index to jump to.
|
||||||
|
|
||||||
|
|
||||||
## OP_NEW_SCOPE
|
## OP_NEW_SCOPE
|
||||||
|
|
||||||
creates a new stack
|
creates a new stack
|
||||||
|
|
||||||
|
## OP_EMPTY_SCOPE
|
||||||
|
|
||||||
|
empties the current scope so the same memory can be reused.
|
||||||
|
|
||||||
## OP_POP_SCOPE
|
## OP_POP_SCOPE
|
||||||
|
|
||||||
pops the top scope off the current
|
pops the top scope off the current
|
||||||
@@ -108,9 +120,9 @@ sets the source location onto the runtime
|
|||||||
1. the column
|
1. the column
|
||||||
1. the length
|
1. the length
|
||||||
|
|
||||||
## OP_LOAD_ACCESS_FUNCTION
|
## OP_LOAD_GETATTRIBUTE_METHOD
|
||||||
|
|
||||||
loads the access function into register 1
|
loads the \_\_getattribute\_\_ method from the objects class in register 1 and put it into register 1
|
||||||
|
|
||||||
## OP_LOAD_BOOL
|
## OP_LOAD_BOOL
|
||||||
|
|
||||||
@@ -120,19 +132,59 @@ loads a boolean into register 1
|
|||||||
|
|
||||||
## OP_LOAD_NUMBER
|
## OP_LOAD_NUMBER
|
||||||
|
|
||||||
loads a mpq_t number into memory
|
loads a mpq_t / int64 number into memory
|
||||||
|
|
||||||
1. the register to write to. (*)
|
1. the register to write to. (*)
|
||||||
|
1. is int64 (*)
|
||||||
1. the size of the numerator in the constant buffer.
|
1. the size of the numerator in the constant buffer.
|
||||||
1. the offset in the constant buffer of the numerator.
|
1. the offset in the constant buffer of the numerator.
|
||||||
1. is integer. (*)
|
1. is integer. (*)
|
||||||
1. the size of the denominator in the constant buffer.
|
1. the size of the denominator in the constant buffer.
|
||||||
1. the offset in the constant buffer of the denominator.
|
1. the offset in the constant buffer of the denominator.
|
||||||
|
|
||||||
## OP_LOAD_ADDITION_FUNCTION
|
## OP_COPY_TO_REGISTER
|
||||||
|
|
||||||
loads the addition function into register 1
|
copies the value from one register to another
|
||||||
|
|
||||||
## OP_LOAD_SUBTRACTION_FUNCTION
|
1. the register to copy from (*)
|
||||||
|
2. the register to write to (*)
|
||||||
|
|
||||||
loads the subtraction function into register 1
|
## OP_ADDITION
|
||||||
|
|
||||||
|
performs an addition between register A and register B, storing the result in register C
|
||||||
|
|
||||||
|
1. the register A (*)
|
||||||
|
2. the register B (*)
|
||||||
|
2. the register C (*)
|
||||||
|
|
||||||
|
## OP_SUBTRACTION
|
||||||
|
|
||||||
|
performs an subtraction between register A and register B, storing the result in register C
|
||||||
|
|
||||||
|
1. the register A (*)
|
||||||
|
2. the register B (*)
|
||||||
|
2. the register C (*)
|
||||||
|
|
||||||
|
## OP_MULTIPLICATION
|
||||||
|
|
||||||
|
performs an multiplication between register A and register B, storing the result in register C
|
||||||
|
|
||||||
|
1. the register A (*)
|
||||||
|
2. the register B (*)
|
||||||
|
2. the register C (*)
|
||||||
|
|
||||||
|
## OP_DIVISION
|
||||||
|
|
||||||
|
performs an division between register A and register B, storing the result in register C
|
||||||
|
|
||||||
|
1. the register A (*)
|
||||||
|
2. the register B (*)
|
||||||
|
2. the register C (*)
|
||||||
|
|
||||||
|
## OP_NOT
|
||||||
|
|
||||||
|
inverts the boolean value in register 0.
|
||||||
|
|
||||||
|
## OP_LOAD_SETATTR_METHOD
|
||||||
|
|
||||||
|
loads the \_\_setattr\_\_ method from the objects class in register 1 and put it into register 1
|
||||||
@@ -14,17 +14,18 @@
|
|||||||
size_t translate_parsed_function(Translated *translated,
|
size_t translate_parsed_function(Translated *translated,
|
||||||
ParsedFunction *parsedFunction, ArErr *err) {
|
ParsedFunction *parsedFunction, ArErr *err) {
|
||||||
DArray main_bytecode = translated->bytecode;
|
DArray main_bytecode = translated->bytecode;
|
||||||
DArray _temp_bytecode;
|
uint8_t old_assignment = translated->registerAssignment;
|
||||||
darray_init(&_temp_bytecode, sizeof(uint8_t));
|
translated->registerAssignment = 1;
|
||||||
|
darray_init(&translated->bytecode, sizeof(uint8_t));
|
||||||
set_registers(translated, 1);
|
set_registers(translated, 1);
|
||||||
translated->bytecode = _temp_bytecode;
|
|
||||||
translate_parsed(translated, parsedFunction->body, err);
|
translate_parsed(translated, parsedFunction->body, err);
|
||||||
size_t function_bytecode_offset =
|
size_t function_bytecode_offset =
|
||||||
arena_push(&translated->constants, translated->bytecode.data,
|
arena_push(&translated->constants, translated->bytecode.data,
|
||||||
translated->bytecode.size*translated->bytecode.element_size);
|
translated->bytecode.size*translated->bytecode.element_size);
|
||||||
size_t function_bytecode_length = translated->bytecode.size;
|
size_t function_bytecode_length = translated->bytecode.size;
|
||||||
|
darray_free(&translated->bytecode, NULL);
|
||||||
translated->bytecode = main_bytecode;
|
translated->bytecode = main_bytecode;
|
||||||
darray_free(&_temp_bytecode, NULL);
|
translated->registerAssignment = old_assignment;
|
||||||
size_t start = push_instruction_byte(translated, OP_LOAD_FUNCTION);
|
size_t start = push_instruction_byte(translated, OP_LOAD_FUNCTION);
|
||||||
size_t offset = arena_push(&translated->constants, parsedFunction->name,
|
size_t offset = arena_push(&translated->constants, parsedFunction->name,
|
||||||
strlen(parsedFunction->name));
|
strlen(parsedFunction->name));
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ size_t translate_parsed_if(Translated *translated, DArray *parsedIf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
push_instruction_byte(translated, OP_BOOL);
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
push_instruction_byte(translated, 0);
|
|
||||||
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
||||||
push_instruction_byte(translated, 0);
|
push_instruction_byte(translated, 0);
|
||||||
uint64_t last_jump_index = push_instruction_code(translated, 0);
|
uint64_t last_jump_index = push_instruction_code(translated, 0);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "number.h"
|
#include "number.h"
|
||||||
|
#include "../../runtime/objects/number/number.h"
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -16,6 +17,13 @@ size_t translate_parsed_number(Translated *translated, mpq_t *number,
|
|||||||
set_registers(translated, to_register + 1);
|
set_registers(translated, to_register + 1);
|
||||||
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
|
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
|
||||||
push_instruction_byte(translated, to_register);
|
push_instruction_byte(translated, to_register);
|
||||||
|
int64_t i64;
|
||||||
|
uint8_t is_int64 = mpq_to_int64(*number, &i64);
|
||||||
|
push_instruction_byte(translated, is_int64);
|
||||||
|
if (is_int64) {
|
||||||
|
push_instruction_code(translated, i64);
|
||||||
|
return start;
|
||||||
|
}
|
||||||
size_t num_size;
|
size_t num_size;
|
||||||
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
|
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
|
||||||
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
|
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
|
||||||
|
|||||||
@@ -6,36 +6,94 @@
|
|||||||
|
|
||||||
#include "operation.h"
|
#include "operation.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
size_t translate_operation(Translated *translated, ParsedOperation *operation,
|
size_t translate_operation(Translated *translated, ParsedOperation *operation,
|
||||||
ArErr *err) {
|
ArErr *err) {
|
||||||
set_registers(translated, 1);
|
if (operation->operation == TOKEN_AND || operation->operation == TOKEN_OR) {
|
||||||
uint64_t first;
|
size_t *jump_to_if_false =
|
||||||
switch (operation->operation) {
|
checked_malloc(operation->to_operate_on.size * sizeof(size_t));
|
||||||
case TOKEN_PLUS:;
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
first = push_instruction_byte(translated, OP_LOAD_ADDITION_FUNCTION);
|
set_registers(translated, translated->registerAssignment);
|
||||||
break;
|
uint64_t first = 0;
|
||||||
case TOKEN_MINUS:
|
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
||||||
first = push_instruction_byte(translated, OP_LOAD_SUBTRACTION_FUNCTION);
|
uint64_t position = translate_parsed(
|
||||||
break;
|
translated, darray_get(&operation->to_operate_on, i), err);
|
||||||
default:
|
if (i == 0)
|
||||||
*err = create_err(operation->line, operation->column, operation->length,
|
first = position;
|
||||||
translated->path, "Syntax Error", "unknown operation");
|
if (err->exists) {
|
||||||
return 0;
|
free(jump_to_if_false);
|
||||||
}
|
return first;
|
||||||
push_instruction_byte(translated, OP_INIT_CALL);
|
}
|
||||||
push_instruction_code(translated, operation->to_operate_on.size);
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
|
||||||
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
|
if (operation->operation == TOKEN_OR) push_instruction_byte(translated, OP_NOT);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
jump_to_if_false[i] = push_instruction_code(translated, 0);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
||||||
|
set_instruction_code(translated, jump_to_if_false[i],
|
||||||
|
translated->bytecode.size);
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
|
||||||
|
free(jump_to_if_false);
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
|
uint8_t registerB = translated->registerAssignment++;
|
||||||
|
set_registers(translated, translated->registerAssignment);
|
||||||
|
uint64_t first = translate_parsed(
|
||||||
|
translated, darray_get(&operation->to_operate_on, 0), err);
|
||||||
|
if (err->exists)
|
||||||
|
return first;
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
for (size_t i = 1; i < operation->to_operate_on.size; i++) {
|
||||||
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
|
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
if (err->exists)
|
||||||
push_instruction_code(translated, i);
|
return first;
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerB);
|
||||||
|
switch (operation->operation) {
|
||||||
|
case TOKEN_PLUS:;
|
||||||
|
push_instruction_byte(translated, OP_ADDITION);
|
||||||
|
break;
|
||||||
|
case TOKEN_MINUS:;
|
||||||
|
push_instruction_byte(translated, OP_SUBTRACTION);
|
||||||
|
break;
|
||||||
|
case TOKEN_STAR:;
|
||||||
|
push_instruction_byte(translated, OP_MULTIPLICATION);
|
||||||
|
break;
|
||||||
|
case TOKEN_SLASH:;
|
||||||
|
push_instruction_byte(translated, OP_DIVISION);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*err = create_err(operation->line, operation->column, operation->length,
|
||||||
|
translated->path, "Syntax Error", "unknown operation");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, registerB);
|
||||||
|
push_instruction_byte(
|
||||||
|
translated, operation->to_operate_on.size - 1 == i ? 0 : registerA);
|
||||||
}
|
}
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
push_instruction_byte(translated, registerA);
|
||||||
push_instruction_code(translated, operation->line);
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
push_instruction_code(translated, operation->column);
|
push_instruction_byte(translated, registerB);
|
||||||
push_instruction_code(translated, operation->length);
|
translated->registerAssignment -= 2;
|
||||||
push_instruction_byte(translated, OP_CALL);
|
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
#include "translator.h"
|
#include "translator.h"
|
||||||
#include "../hash_data/hash_data.h"
|
#include "../hash_data/hash_data.h"
|
||||||
|
#include "../parser/not/not.h"
|
||||||
#include "access/access.h"
|
#include "access/access.h"
|
||||||
|
#include "assignment/assignment.h"
|
||||||
#include "call/call.h"
|
#include "call/call.h"
|
||||||
#include "declaration/declaration.h"
|
#include "declaration/declaration.h"
|
||||||
#include "dowrap/dowrap.h"
|
#include "dowrap/dowrap.h"
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
#include "operation/operation.h"
|
#include "operation/operation.h"
|
||||||
#include "return/return.h"
|
#include "return/return.h"
|
||||||
#include "string/string.h"
|
#include "string/string.h"
|
||||||
|
#include "while/while.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -49,10 +52,6 @@ void arena_resize(ConstantArena *arena, size_t new_size) {
|
|||||||
arena->capacity = new_capacity;
|
arena->capacity = new_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *arena_get(ConstantArena *arena, size_t offset) {
|
|
||||||
return arena->data + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t arena_push(ConstantArena *arena, const void *data, size_t length) {
|
size_t arena_push(ConstantArena *arena, const void *data, size_t length) {
|
||||||
uint64_t hash = siphash64_bytes(data, length, siphash_key);
|
uint64_t hash = siphash64_bytes(data, length, siphash_key);
|
||||||
|
|
||||||
@@ -84,6 +83,7 @@ Translated init_translator(char *path) {
|
|||||||
Translated translated;
|
Translated translated;
|
||||||
translated.path = path;
|
translated.path = path;
|
||||||
translated.registerCount = 1;
|
translated.registerCount = 1;
|
||||||
|
translated.registerAssignment = 1;
|
||||||
translated.return_jumps = NULL;
|
translated.return_jumps = NULL;
|
||||||
darray_init(&translated.bytecode, sizeof(uint8_t));
|
darray_init(&translated.bytecode, sizeof(uint8_t));
|
||||||
arena_init(&translated.constants);
|
arena_init(&translated.constants);
|
||||||
@@ -148,6 +148,9 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
|
|||||||
(ParsedIdentifier *)parsedValue->data);
|
(ParsedIdentifier *)parsedValue->data);
|
||||||
case AST_IF:
|
case AST_IF:
|
||||||
return translate_parsed_if(translated, (DArray *)parsedValue->data, err);
|
return translate_parsed_if(translated, (DArray *)parsedValue->data, err);
|
||||||
|
case AST_WHILE:
|
||||||
|
return translate_parsed_while(translated, (ParsedWhile *)parsedValue->data,
|
||||||
|
err);
|
||||||
case AST_DOWRAP:
|
case AST_DOWRAP:
|
||||||
return translate_parsed_dowrap(translated, (DArray *)parsedValue->data,
|
return translate_parsed_dowrap(translated, (DArray *)parsedValue->data,
|
||||||
err);
|
err);
|
||||||
@@ -162,6 +165,17 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
|
|||||||
case AST_OPERATION:
|
case AST_OPERATION:
|
||||||
return translate_operation(translated, (ParsedOperation *)parsedValue->data,
|
return translate_operation(translated, (ParsedOperation *)parsedValue->data,
|
||||||
err);
|
err);
|
||||||
|
case AST_ASSIGN:
|
||||||
|
return translate_parsed_assignment(translated,
|
||||||
|
(ParsedAssign *)parsedValue->data, err);
|
||||||
|
case AST_TO_BOOL: {
|
||||||
|
size_t first = translate_parsed(
|
||||||
|
translated, ((ParsedToBool *)parsedValue->data)->value, err);
|
||||||
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
|
if (((ParsedToBool *)parsedValue->data)->invert)
|
||||||
|
push_instruction_byte(translated, OP_NOT);
|
||||||
|
return first;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,22 +24,27 @@ typedef enum {
|
|||||||
OP_JUMP_IF_FALSE,
|
OP_JUMP_IF_FALSE,
|
||||||
OP_JUMP,
|
OP_JUMP,
|
||||||
OP_NEW_SCOPE,
|
OP_NEW_SCOPE,
|
||||||
|
OP_EMPTY_SCOPE,
|
||||||
OP_POP_SCOPE,
|
OP_POP_SCOPE,
|
||||||
OP_INIT_CALL,
|
OP_INIT_CALL,
|
||||||
OP_INSERT_ARG,
|
OP_INSERT_ARG,
|
||||||
OP_CALL,
|
OP_CALL,
|
||||||
OP_SOURCE_LOCATION,
|
OP_SOURCE_LOCATION,
|
||||||
OP_LOAD_ACCESS_FUNCTION,
|
|
||||||
OP_LOAD_BOOL,
|
OP_LOAD_BOOL,
|
||||||
OP_LOAD_NUMBER,
|
OP_LOAD_NUMBER,
|
||||||
OP_LOAD_ADDITION_FUNCTION,
|
OP_ASSIGN,
|
||||||
OP_LOAD_SUBTRACTION_FUNCTION
|
OP_COPY_TO_REGISTER,
|
||||||
|
OP_ADDITION,
|
||||||
|
OP_SUBTRACTION,
|
||||||
|
OP_LOAD_GETATTRIBUTE_METHOD,
|
||||||
|
OP_MULTIPLICATION,
|
||||||
|
OP_DIVISION,
|
||||||
|
OP_NOT,
|
||||||
|
OP_LOAD_SETATTR_METHOD
|
||||||
} OperationType;
|
} OperationType;
|
||||||
|
|
||||||
void arena_resize(ConstantArena *arena, size_t new_size);
|
void arena_resize(ConstantArena *arena, size_t new_size);
|
||||||
|
|
||||||
void *arena_get(ConstantArena *arena, size_t offset);
|
|
||||||
|
|
||||||
size_t arena_push(ConstantArena *arena, const void *data, size_t length);
|
size_t arena_push(ConstantArena *arena, const void *data, size_t length);
|
||||||
|
|
||||||
size_t push_instruction_byte(Translated *translator, uint8_t byte);
|
size_t push_instruction_byte(Translated *translator, uint8_t byte);
|
||||||
|
|||||||
55
src/translator/while/while.c
Normal file
55
src/translator/while/while.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "while.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile,
|
||||||
|
ArErr *err) {
|
||||||
|
set_registers(translated, 1);
|
||||||
|
DArray return_jumps;
|
||||||
|
DArray *old_return_jumps = NULL;
|
||||||
|
if (translated->return_jumps) {
|
||||||
|
darray_init(&return_jumps, sizeof(size_t));
|
||||||
|
old_return_jumps = translated->return_jumps;
|
||||||
|
translated->return_jumps = &return_jumps;
|
||||||
|
}
|
||||||
|
size_t first = push_instruction_byte(translated, OP_NEW_SCOPE);
|
||||||
|
size_t start_of_loop =
|
||||||
|
translate_parsed(translated, parsedWhile->condition, err);
|
||||||
|
if (err->exists) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
|
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
uint64_t jump_index = push_instruction_code(translated, 0);
|
||||||
|
translate_parsed(translated, parsedWhile->content, err);
|
||||||
|
push_instruction_byte(translated, OP_EMPTY_SCOPE);
|
||||||
|
push_instruction_byte(translated, OP_JUMP);
|
||||||
|
push_instruction_code(translated, start_of_loop);
|
||||||
|
set_instruction_code(translated, jump_index, translated->bytecode.size);
|
||||||
|
push_instruction_byte(translated, OP_POP_SCOPE);
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
if (translated->return_jumps) {
|
||||||
|
push_instruction_byte(translated, OP_JUMP);
|
||||||
|
size_t skip_return = push_instruction_code(translated, 0);
|
||||||
|
|
||||||
|
size_t return_jump_to = push_instruction_byte(translated, OP_POP_SCOPE);
|
||||||
|
push_instruction_byte(translated, OP_JUMP);
|
||||||
|
size_t return_up = push_instruction_code(translated, 0);
|
||||||
|
darray_push(old_return_jumps, &return_up);
|
||||||
|
for (size_t i = 0; i < return_jumps.size; i++) {
|
||||||
|
size_t *index = darray_get(&return_jumps, i);
|
||||||
|
set_instruction_code(translated, *index, return_jump_to);
|
||||||
|
}
|
||||||
|
set_instruction_code(translated, skip_return, translated->bytecode.size);
|
||||||
|
darray_free(&return_jumps, NULL);
|
||||||
|
translated->return_jumps = old_return_jumps;
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
15
src/translator/while/while.h
Normal file
15
src/translator/while/while.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TRANSLATE_WHILE_H
|
||||||
|
#define TRANSLATE_WHILE_H
|
||||||
|
#include "../translator.h"
|
||||||
|
#include "../../parser/while/while.h"
|
||||||
|
|
||||||
|
size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile,
|
||||||
|
ArErr *err);
|
||||||
|
|
||||||
|
#endif // TRANSLATE_WHILE_H
|
||||||
94
test.ar
94
test.ar
@@ -1,94 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
"h"
|
|
||||||
"e"
|
|
||||||
"ll"
|
|
||||||
"o"
|
|
||||||
" "
|
|
||||||
"wo"
|
|
||||||
"rl"
|
|
||||||
"d"
|
|
||||||
"world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello\u0000world"
|
|
||||||
"🇬🇧"
|
|
||||||
"\u0000"
|
|
||||||
"hello"
|
|
||||||
|
|
||||||
let hello = "helllo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbruhhhhh"
|
|
||||||
|
|
||||||
1.24323234e2312324
|
|
||||||
|
|
||||||
let a,
|
|
||||||
b = "hello",
|
|
||||||
c,
|
|
||||||
d = 42,
|
|
||||||
temp_result,
|
|
||||||
compute_area(radius) = 3.1415,
|
|
||||||
identity(x) = x,
|
|
||||||
f(x)=do
|
|
||||||
term.log("hello world")
|
|
||||||
do
|
|
||||||
term.log('hello world')
|
|
||||||
term.log("hello world")
|
|
||||||
,
|
|
||||||
g(y, z),
|
|
||||||
result,
|
|
||||||
z = 0,
|
|
||||||
extremely_long_variable_name_to_test_limits,
|
|
||||||
cache_value = compute_area(5),
|
|
||||||
placeholder_fn_with_no_body(arg1, arg2, arg3),
|
|
||||||
total = identity(100),
|
|
||||||
deeply_nested_args_function(arg1, arg2, arg3, arg4, arg5),
|
|
||||||
sum = a,
|
|
||||||
another,
|
|
||||||
another_function(),
|
|
||||||
just_null_here,
|
|
||||||
x
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (x) do
|
|
||||||
term.log("hello world")
|
|
||||||
term.log("hello world")
|
|
||||||
else term.log("bruh")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mm=x/2/4/2/4354/534/534//534//3422*404203420234+3432423324&&430234230||4320423040230423^384239423043024923%4432042304920.3432423423
|
|
||||||
|
|
||||||
let X = [
|
|
||||||
'hello world',
|
|
||||||
'wow',
|
|
||||||
10
|
|
||||||
]
|
|
||||||
|
|
||||||
term.log(x[0:1:1])
|
|
||||||
|
|
||||||
let y = {
|
|
||||||
'hello':test,
|
|
||||||
world:'nice'
|
|
||||||
}
|
|
||||||
|
|
||||||
term.log(y['hello'],y.world)
|
|
||||||
38
test.py
38
test.py
@@ -1,38 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import string
|
|
||||||
from itertools import product
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def generate_names(max_width, skip_keywords=None):
|
|
||||||
if skip_keywords is None:
|
|
||||||
skip_keywords = {"if", "else", "while", "forever", "for", "break", "continue",
|
|
||||||
"return", "let", "import", "from", "do", "true", "false", "null",
|
|
||||||
"delete", "not", "try", "catch", "in", "or", "and", "elif"}
|
|
||||||
else:
|
|
||||||
skip_keywords = set(skip_keywords)
|
|
||||||
|
|
||||||
chars = string.ascii_lowercase
|
|
||||||
first = True
|
|
||||||
write = sys.stdout.write
|
|
||||||
|
|
||||||
for length in range(1, max_width + 1):
|
|
||||||
print(length, file=sys.stderr)
|
|
||||||
i = 0
|
|
||||||
for p in product(chars, repeat=length):
|
|
||||||
name = ''.join(p)
|
|
||||||
if name in skip_keywords:
|
|
||||||
continue
|
|
||||||
write('let ')
|
|
||||||
write(name)
|
|
||||||
write(' = null\n')
|
|
||||||
first = False
|
|
||||||
if i>10000000:
|
|
||||||
break
|
|
||||||
i+=1
|
|
||||||
|
|
||||||
# Example usage:
|
|
||||||
max_width = 5
|
|
||||||
generate_names(max_width)
|
|
||||||
10
testing.ar
10
testing.ar
@@ -1,10 +0,0 @@
|
|||||||
let say_hi(name) = do
|
|
||||||
let z(y) = do
|
|
||||||
return y
|
|
||||||
let u = z(
|
|
||||||
do
|
|
||||||
return name
|
|
||||||
)
|
|
||||||
return "hello "+u+", how are you?"
|
|
||||||
|
|
||||||
term.log(say_hi("william"))
|
|
||||||
1
tests/anonymous_function.ar
Normal file
1
tests/anonymous_function.ar
Normal file
@@ -0,0 +1 @@
|
|||||||
|
term.log(()=10)
|
||||||
1
tests/env.ar
Normal file
1
tests/env.ar
Normal file
@@ -0,0 +1 @@
|
|||||||
|
term.log("hello,", env.USER+'.', 'how is', env.XDG_SESSION_TYPE+'?')
|
||||||
10
tests/intergral.ar
Normal file
10
tests/intergral.ar
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
let f(x) = sin(x)
|
||||||
|
|
||||||
|
let intergral_aprox(n, a, b) = do
|
||||||
|
let h = (b-a)/n
|
||||||
|
let output = 0
|
||||||
|
for (i from 1 to n+1) do
|
||||||
|
output += h*f(a+i*h)
|
||||||
|
return output
|
||||||
|
|
||||||
|
term.log(intergral_aprox(1000, 0,1))
|
||||||
4
tests/iteration-test.ar
Normal file
4
tests/iteration-test.ar
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
term.log(global)
|
||||||
|
let i = 1e8
|
||||||
|
while (i) do
|
||||||
|
i=i-1
|
||||||
3
tests/iteration-test.py
Normal file
3
tests/iteration-test.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
i = 1000000
|
||||||
|
while i:
|
||||||
|
i=i-1
|
||||||
6
tests/number-memory-leak.ar
Normal file
6
tests/number-memory-leak.ar
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
let i = 10
|
||||||
|
let x = 1
|
||||||
|
while (i) do
|
||||||
|
x = x * 1e100000000
|
||||||
|
term.log(i=i-1)
|
||||||
|
term.log(x)
|
||||||
12
windows-profile.txt
Normal file
12
windows-profile.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[settings]
|
||||||
|
os=Windows
|
||||||
|
compiler=gcc
|
||||||
|
compiler.version=12
|
||||||
|
compiler.libcxx=libstdc++11
|
||||||
|
compiler.threads=posix
|
||||||
|
compiler.exception=seh
|
||||||
|
arch=x86_64
|
||||||
|
build_type=Release
|
||||||
|
|
||||||
|
[tool_requires]
|
||||||
|
mingw-builds/12.2.0
|
||||||
Reference in New Issue
Block a user