Compare commits

...

97 Commits

Author SHA1 Message Date
William Bell
6d3e79b731 fix window build 2025-10-21 21:32:02 +01:00
William Bell
b3ee64d294 fix windows build 2025-10-21 21:08:27 +01:00
William Bell
e6ec0fa38a fix windows building 2025-10-21 20:57:22 +01:00
William Bell
c8394228b3 add function assignment 2025-10-21 20:34:33 +01:00
70ba81bebc change to __set_attr__ 2025-09-19 00:31:04 +01:00
William Bell
50ff9fbefc add __setattr__ 2025-09-17 22:56:44 +01:00
William Bell
042c278b8d Merge remote-tracking branch 'refs/remotes/origin/main' 2025-09-17 17:26:41 +01:00
William Bell
81efaaac07 fix path bug 2025-09-17 17:25:42 +01:00
3b0ec79955 start adding set attribute support 2025-09-17 17:24:50 +01:00
William Bell
4be8e8e32f add __repr__ 2025-09-13 01:17:16 +01:00
William Bell
5846adf025 add dictionary string 2025-09-13 01:01:35 +01:00
William Bell
daa8056b7a add license to shell 2025-09-12 01:21:08 +01:00
William Bell
1a5abd9543 impliment micro optimisations by reordering and restructing the structs so they are smaller. 2025-09-09 18:41:19 +01:00
William Bell
774890de1d change the built in slots to be allocated on the fly, making the objects smaller but faster 2025-09-09 17:55:54 +01:00
William Bell
fc7cfc7cfb change how access is done and add built in array (need to optimise the size) 2025-09-09 06:24:23 +01:00
William Bell
d46a6dc209 improve performance by using an inline locals array in hashmaps 2025-09-08 02:21:26 +01:00
William Bell
23c4a7ebd1 add not and or, while also improving performance. 2025-09-07 21:03:57 +01:00
William Bell
57728af0b6 add multiplication, division, and && 2025-09-03 05:21:41 +01:00
William Bell
df040adf45 get functions to use a new register assignment, since they get new registers now 2025-09-02 22:31:01 +01:00
William Bell
c2e0cdc6d6 fix buffer overflow seg fault when using cache 2025-09-02 18:35:43 +01:00
William Bell
571efe46b7 fix buffer overflow seg fault when using cache 2025-09-02 18:35:36 +01:00
William Bell
67569bffc2 shitty boehm is dereferencing 0x20 for some stupid reason 2025-09-02 05:06:48 +01:00
William Bell
f5ee0f6fc8 fix operations not performing correctly and trying to fix cached code not executing correctly 2025-09-02 02:59:47 +01:00
William Bell
fd5b237dfe set up so reusing scope when in a loop 2025-09-01 23:09:09 +01:00
William Bell
322716af0c remove debug print 2025-09-01 22:11:54 +01:00
William Bell
c67b37d8b2 remove performance spec 2025-09-01 21:51:49 +01:00
William Bell
b9c0503d54 keep loop using the same dispatch table, removing the need to recreate the dispatch table 2025-09-01 21:51:16 +01:00
William Bell
19268f3070 improve performance massively from 0.9 seconds to 0.38 seconds :) 2025-09-01 20:25:47 +01:00
William Bell
4f91bf48f3 improve performance for integers 2025-08-30 03:29:02 +01:00
William Bell
4fc28d3b76 fix seg fault in optimised builds 2025-08-29 13:42:21 +01:00
c01dee80b0 add bool value to speed up primitives 2025-08-29 12:58:02 +01:00
0f0a3f5d31 change to dispatch table to hopefully improve speed 2025-08-29 12:22:35 +01:00
William Bell
f598c215e7 start adding assignment (currently only identifier assignment works) 2025-08-29 01:41:53 +01:00
William Bell
fff4f6bcb5 add while loop 2025-08-28 04:07:19 +01:00
William Bell
c322d5680f fix double free 2025-08-27 16:16:32 +01:00
William Bell
db650d8ccf add anonymous functions 2025-08-26 02:13:48 +01:00
William Bell
6ad0b2c02e switch allocations to atomic to improve performance 2025-08-20 00:26:35 +01:00
William Bell
624a54c90c remove gmp-x86_64.h 2025-08-19 02:41:41 +01:00
William Bell
c856e7d654 add multiplication and division 2025-08-19 02:36:09 +01:00
William Bell
a96023ced1 fix for winblows 2025-08-18 15:03:11 +01:00
William Bell
1908d9bbbb fix for winblows 2025-08-18 14:43:49 +01:00
William Bell
47db2ca27d fix for winblows 2025-08-18 06:40:59 +01:00
William Bell
2e7b3b4baa fix for winblows 2025-08-18 06:38:30 +01:00
William Bell
24163e3389 fix gmp bug 2025-08-18 06:25:29 +01:00
William Bell
0c0832d131 add shell and stdin piping support 2025-08-18 06:22:13 +01:00
William Bell
1742a0c52d add shell and stdin piping support 2025-08-18 06:22:00 +01:00
William Bell
224039ba43 fix arch name 2025-08-17 01:30:18 +01:00
William Bell
5e7ce495e4 fix runner 2025-08-17 01:12:52 +01:00
William Bell
35a0f35cf8 add native arm support 2025-08-17 00:49:34 +01:00
William Bell
f9490ceac0 bloody ai 2025-08-16 18:28:50 +01:00
William Bell
4cda311008 bloody ai 2025-08-16 18:25:46 +01:00
William Bell
b3aa653076 incorrect environment variable assignment 2025-08-16 18:20:12 +01:00
William Bell
fc3321bcf0 incorrect package name 2025-08-16 18:18:00 +01:00
William Bell
868b3bfc3d change to cross compile linux 2025-08-16 18:15:32 +01:00
William Bell
f5e241aba0 forgot to add cmake and make 2025-08-16 16:08:06 +01:00
William Bell
8c3ee3fe05 fix --break-system-packages 2025-08-16 15:42:34 +01:00
William Bell
eb285b6e8f add linux arm64 to builds and reshape how execution is done. 2025-08-16 15:25:33 +01:00
William Bell
78a1edd572 add calculation to test 2025-08-16 05:40:29 +01:00
William Bell
b905026010 fix rosetta not used 2025-08-16 04:31:21 +01:00
William Bell
677afd9433 fix using Rosetta 2025-08-16 04:10:57 +01:00
William Bell
757da3f973 stupid ai 2025-08-16 03:51:05 +01:00
William Bell
5a86510c3b fix release for macos x86_64 and arm64 2025-08-16 03:48:48 +01:00
William Bell
fb8b6a89ae build for more architectures 2025-08-16 03:41:32 +01:00
William Bell
6ddf9953e7 change windows builds to tar.gz 2025-08-16 03:23:01 +01:00
William Bell
1609227a42 add bcrypt for windows 2025-08-16 03:10:50 +01:00
William Bell
51f6a88ce8 add profile to build 2025-08-16 03:00:01 +01:00
William Bell
f420273471 fix backslashes 2025-08-16 02:46:33 +01:00
William Bell
4b2a747338 use msys/flex 2025-08-16 02:36:47 +01:00
William Bell
5277814af0 fix conan 2025-08-16 02:31:15 +01:00
William Bell
8928ab2d99 add cmake as dependency 2025-08-16 02:20:57 +01:00
William Bell
d08b307c6e add python as a dependency 2025-08-16 02:12:55 +01:00
William Bell
6474329afc switch to conan for windows 2025-08-16 02:08:56 +01:00
William Bell
c49e67c839 switch windows to use conan 2025-08-16 02:04:00 +01:00
William Bell
25cb96e473 try get it to be static 2025-08-16 01:57:56 +01:00
William Bell
f11890a8b3 fix linking for linux and macos 2025-08-16 01:39:44 +01:00
William Bell
59b1d222c2 fix cmake 2025-08-16 01:32:57 +01:00
William Bell
2fba132016 make gc and gmp static and math dynamic 2025-08-16 01:22:08 +01:00
William Bell
bddc2cdc79 fix release to merge multiple 2025-08-16 01:06:06 +01:00
William Bell
e1b80b42d9 fix make release 2025-08-16 01:02:48 +01:00
William Bell
dab86925b4 fix winblows 2025-08-16 00:58:56 +01:00
William Bell
0f45052dce fix for winblows 2025-08-16 00:56:35 +01:00
William Bell
68f4207216 fix for winblows 2025-08-16 00:54:33 +01:00
William Bell
f9f8ca08c6 fix bug for windows 2025-08-16 00:50:23 +01:00
William Bell
0666b02c13 fix flex tool 2025-08-16 00:44:00 +01:00
William Bell
1654507835 fix for windows 2025-08-16 00:42:13 +01:00
William Bell
d054ece8e2 release 2025-08-16 00:39:37 +01:00
William Bell
4937942d6e fix release 2025-08-16 00:35:48 +01:00
William Bell
82ea92183f fix release 2025-08-16 00:28:08 +01:00
William Bell
5fb15b476f fix release 2025-08-16 00:26:26 +01:00
William Bell
d1a455dbbe fix release.yml 2025-08-16 00:07:10 +01:00
William Bell
a81640747d fix release.yml 2025-08-15 22:07:25 +01:00
William Bell
4a1ed23f96 fix release.yml 2025-08-15 22:05:57 +01:00
William Bell
eb36d02fcb fix release.yml 2025-08-15 22:03:23 +01:00
William Bell
7b3a1e1835 fix release.yml 2025-08-15 21:52:16 +01:00
William Bell
8e53579682 fix release.yml 2025-08-15 21:36:51 +01:00
William Bell
0d8f262185 this thing is really annoying me now 2025-08-15 21:34:31 +01:00
William Bell
fc6f41d89b fix release.yml 2025-08-15 21:30:01 +01:00
84 changed files with 6804 additions and 1666 deletions

View File

@@ -10,8 +10,8 @@ on:
- '*' # Any tag - '*' # Any tag
jobs: jobs:
build-linux: build-linux-x86_64:
runs-on: ubuntu-latest runs-on: ubuntu-latest # build both architectures
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@@ -51,18 +51,17 @@ jobs:
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: linux-artifact name: linux-x86_64-artifact
path: ${{ env.TAR_NAME }} path: ${{ env.TAR_NAME }}
build-linux-arm64:
build-macos: runs-on: ubuntu-22.04-arm # build both architectures
runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Install build tools - name: Install build tools
run: brew install flex bison run: sudo apt-get update && sudo apt-get install -y flex bison
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@@ -95,19 +94,21 @@ jobs:
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: macos-artifact name: linux-arm64-artifact
path: ${{ env.TAR_NAME }} path: ${{ env.TAR_NAME }}
build-windows: build-macos:
runs-on: windows-latest runs-on: macos-latest
strategy:
matrix:
arch: [x86_64, arm64] # build both architectures
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Install build tools - name: Install build tools
run: choco install winflexbison -y run: brew install flex bison
shell: pwsh
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@@ -118,26 +119,97 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install conan pip install conan
if [ "${{ matrix.arch }}" = "x86_64" ] && [ "$(uname -m)" = "arm64" ]; then
arch -x86_64 conan profile detect
else
conan profile detect conan profile detect
shell: pwsh fi
- name: Build with MinGW - name: Build
run: | run: |
conan install . BUILD_DIR="build_${{ matrix.arch }}"
conan build . mkdir -p "$BUILD_DIR"
shell: pwsh 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 - name: Package
run: | run: |
$TAG = $env:GITHUB_REF -replace 'refs/tags/', '' TAG=${GITHUB_REF##refs/tags/}
$ARCH = if ([Environment]::Is64BitOperatingSystem) { 'x64' } else { 'x86' } OS="macos"
$FOLDER = "chloride-$TAG-windows-$ARCH" ARCH="${{ matrix.arch }}"
$ZIP = "$FOLDER.zip" FOLDER="chloride-$TAG-$OS-$ARCH"
Rename-Item build\bin $FOLDER TAR="$FOLDER.tar.gz"
Copy-Item LICENSE.txt $FOLDER mv build/bin "$FOLDER"
Compress-Archive -Path $FOLDER -DestinationPath $ZIP cp LICENSE.txt "$FOLDER"
echo "TAR_NAME=$ZIP" >> $env:GITHUB_ENV tar -czf "$TAR" "$FOLDER"
shell: pwsh 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 - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -147,12 +219,13 @@ jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-linux, build-macos, build-windows] needs: [build-linux-x86_64, build-linux-arm64, build-macos, build-windows]
steps: steps:
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
path: ./artifacts path: ./artifacts
merge-multiple: true
- name: Create GitHub Release - name: Create GitHub Release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1

1
.gitignore vendored
View File

@@ -64,5 +64,6 @@ build
*.yy.c *.yy.c
*.yy.h *.yy.h
__isotope__
__arcache__ __arcache__
argon_modules argon_modules

3
.gitmodules vendored
View File

@@ -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
View File

@@ -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": [],

View File

@@ -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)
@@ -51,25 +59,13 @@ set_target_properties(argon PROPERTIES
find_package(BDWgc REQUIRED) find_package(BDWgc REQUIRED)
find_package(gmp REQUIRED) find_package(gmp REQUIRED)
target_compile_options(argon PRIVATE -O3 -Wall -s) target_compile_options(argon PRIVATE -O3 -Wall -Wextra -Wno-unused-function -s)
if(MSVC)
# Disable warning C4061 (enum in switch not handled)
target_compile_options(argon PRIVATE /wd4061)
# Disable Spectre mitigation warning C5045
target_compile_options(argon PRIVATE /wd5045)
# Optionally, remove "treat warnings as errors" if enabled
# target_compile_options(argon PRIVATE /WX-) # uncomment if you previously used /WX
endif()
if(NOT APPLE)
target_link_options(argon PRIVATE -static)
endif()
target_link_libraries(argon PRIVATE target_link_libraries(argon PRIVATE
BDWgc::BDWgc BDWgc::BDWgc
gmp::gmp gmp::gmp
m m
$<$<PLATFORM_ID:Windows>:bcrypt>
) )
target_include_directories(argon PRIVATE target_include_directories(argon PRIVATE

View File

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

4
app.py
View File

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

View File

@@ -33,11 +33,6 @@ class ArgonConan(ConanFile):
os.environ["CONAN_NON_INTERACTIVE"] = "1" os.environ["CONAN_NON_INTERACTIVE"] = "1"
tc = CMakeToolchain(self) tc = CMakeToolchain(self)
if os.name == "nt": # Windows
flex_path = which("win_flex") or which("win_flex.exe")
if not flex_path:
raise Exception("win_flex not found in PATH. Install winflexbison via choco.")
else:
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 Linux/macOS.") raise Exception("Flex not found in system PATH. Please install flex on Linux/macOS.")

View File

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

Submodule external/linenoise added at d895173d67

View File

@@ -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()

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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);

View File

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

View File

@@ -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
View 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(&register_count, 1, sizeof(register_count), bytecode_file) !=
sizeof(register_count)) {
goto FAILED;
}
uint64_t constantsSize;
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
sizeof(constantsSize)) {
goto FAILED;
}
constantsSize = le64toh(constantsSize);
uint64_t bytecodeSize;
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
sizeof(bytecodeSize)) {
goto FAILED;
}
bytecodeSize = le64toh(bytecodeSize);
*translated_dest = init_translator(source_path);
translated_dest->registerCount = register_count;
arena_resize(&translated_dest->constants, constantsSize);
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
constantsSize) {
goto FAILED;
}
translated_dest->constants.size = constantsSize;
darray_resize(&translated_dest->bytecode, bytecodeSize);
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
bytecodeSize) {
goto FAILED;
}
translated_dest->bytecode.size = bytecodeSize;
fprintf(stderr, "cache exists and is valid, so will be used.\n");
fclose(bytecode_file);
return 0;
FAILED:
fprintf(stderr, "cache is invalid... compiling from source.\n");
fclose(bytecode_file);
return 1;
}
Translated load_argon_file(char *path, ArErr *err) {
clock_t start, end;
clock_t beginning = clock();
double time_spent, total_time_spent = 0;
const char *basename_ptr;
size_t basename_length;
cwk_path_get_basename(path, &basename_ptr, &basename_length);
if (!basename_ptr) {
*err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'",
path);
return (Translated){};
}
char basename[FILENAME_MAX];
memcpy(basename, basename_ptr, basename_length);
size_t parent_directory_length;
cwk_path_get_dirname(path, &parent_directory_length);
char parent_directory[FILENAME_MAX];
memcpy(parent_directory, path, parent_directory_length);
parent_directory[parent_directory_length] = '\0';
char cache_folder_path[FILENAME_MAX];
cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path,
sizeof(cache_folder_path));
char cache_file_path[FILENAME_MAX];
cwk_path_join(cache_folder_path, basename, cache_file_path,
sizeof(cache_file_path));
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION,
cache_file_path, sizeof(cache_file_path));
FILE *file = fopen(path, "r");
if (!file) {
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to open file '%s'",
path);
return (Translated){};
}
XXH3_state_t *hash_state = XXH3_createState();
XXH3_64bits_reset(hash_state);
char buffer[8192];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) {
XXH3_64bits_update(hash_state, buffer, bytes);
}
rewind(file);
uint64_t hash = XXH3_64bits_digest(hash_state);
XXH3_freeState(hash_state);
Translated translated;
if (load_cache(&translated, cache_file_path, hash, path) != 0) {
DArray tokens;
darray_init(&tokens, sizeof(Token));
LexerState state = {path, file, 0, 0, &tokens};
start = clock();
*err = lexer(state);
if (err->exists) {
darray_free(&tokens, free_token);
return (Translated){};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent);
fclose(state.file);
DArray ast;
darray_init(&ast, sizeof(ParsedValue));
start = clock();
*err = parser(path, &ast, &tokens, false);
darray_free(&tokens, free_token);
if (err->exists) {
darray_free(&ast, free_parsed);
return (Translated){};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Parser time taken: %f seconds\n", time_spent);
start = clock();
translated = init_translator(path);
*err = translate(&translated, &ast);
darray_free(&ast, free_parsed);
if (err->exists) {
darray_free(&translated.bytecode, NULL);
free(translated.constants.data);
hashmap_free(translated.constants.hashmap, NULL);
return (Translated){};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
fprintf(stderr, "Translation time taken: %f seconds\n", time_spent);
#if defined(__linux__)
malloc_trim(0);
#endif
ensure_dir_exists(cache_folder_path);
file = fopen(cache_file_path, "wb");
uint64_t constantsSize = translated.constants.size;
uint64_t bytecodeSize = translated.bytecode.size;
uint32_t version_number_htole32ed = htole32(version_number);
uint64_t net_hash = htole64(hash);
constantsSize = htole64(constantsSize);
bytecodeSize = htole64(bytecodeSize);
XXH64_state_t *hash_state = XXH64_createState();
XXH64_reset(hash_state, 0);
write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char),
strlen(FILE_IDENTIFIER));
write_and_hash(file, hash_state, &version_number_htole32ed,
sizeof(uint32_t), 1);
write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1);
write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t),
1);
write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1);
write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1);
write_and_hash(file, hash_state, translated.constants.data, 1,
translated.constants.size);
write_and_hash(file, hash_state, translated.bytecode.data,
translated.bytecode.element_size, translated.bytecode.size);
// Finalize the hash
uint64_t file_hash = XXH64_digest(hash_state);
XXH64_freeState(hash_state);
// Convert to little-endian before writing if needed
uint64_t file_hash_le = htole64(file_hash);
fwrite(&file_hash_le, sizeof(file_hash_le), 1, file);
fclose(file);
}
hashmap_free(translated.constants.hashmap, NULL);
Translated gc_translated = {
translated.registerCount, translated.registerAssignment, NULL, {}, {},
translated.path};
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity);
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
View File

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

View File

@@ -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; }

View File

@@ -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, // <=

View File

@@ -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(&register_count, 1, sizeof(register_count), bytecode_file) !=
sizeof(register_count)) {
goto FAILED;
}
uint64_t constantsSize;
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
sizeof(constantsSize)) {
goto FAILED;
}
constantsSize = le64toh(constantsSize);
uint64_t bytecodeSize;
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
sizeof(bytecodeSize)) {
goto FAILED;
}
bytecodeSize = le64toh(bytecodeSize);
*translated_dest = init_translator(source_path);
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

View File

@@ -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); }

View File

@@ -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);

View File

@@ -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));
if (first_token->type == TOKEN_DOT) {
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
parsedAccess->to_access = *to_access; parsedAccess->to_access = to_access;
parsedAccess->access = NULL;
parsedValue->type = AST_ACCESS; parsedValue->type = AST_ACCESS;
parsedValue->data = parsedAccess; parsedValue->data = parsedAccess;
free(to_access);
darray_init(&parsedAccess->access, sizeof(ParsedValue));
if (first_token->type == TOKEN_DOT) {
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);
} }

View File

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

View File

@@ -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, &param);
}
darray_free(&call->args, free_parsed);
is_function = true;
function_assign_to = call->to_call;
switch (function_assign_to->type) {
case AST_IDENTIFIER:
function_name = ((ParsedIdentifier *)function_assign_to->data)->name;
break;
case AST_ACCESS:
if (((ParsedAccess *)function_assign_to->data)->access->type ==
AST_STRING) {
ParsedString *name =
((ParsedAccess *)function_assign_to->data)->access->data;
function_name = checked_malloc(name->length + 1);
function_name[name->length] = 0;
memcpy(function_name, name->string, name->length);
to_free_function_name = true;
break;
}
// FALL THROUGH
default:
function_name = "anonymous";
break;
} }
break; break;
default:; default:;
@@ -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
View File

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

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

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

View File

@@ -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};
} }

View File

@@ -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,8 +29,10 @@ 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));
} }
if (operation_type == current_operation->type) {
darray_push(&positions, &i); darray_push(&positions, &i);
} }
}
ParsedValue parsedValue; ParsedValue parsedValue;
parsedValue.type = AST_OPERATION; parsedValue.type = AST_OPERATION;
ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation)); ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation));
@@ -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);

View File

@@ -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(&parameters, sizeof(char *));
for (size_t i = 0; i < list.size; i++) {
ParsedValue *item = darray_get(&list, i);
if (item->type != AST_IDENTIFIER) {
darray_free(&list, free_parsed);
darray_free(&parameters, free_parameter);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected identifier"),
NULL};
}
char *param = strdup(((ParsedIdentifier *)item->data)->name);
darray_push(&parameters, &param);
}
darray_free(&list, free_parsed);
ParsedValueReturn parsedBody = parse_token(file, tokens, index, true);
if (parsedBody.err.exists) {
darray_free(&parameters, free_parameter);
return parsedBody;
}
return (ParsedValueReturn){
no_err,
create_parsed_function("anonymous", parameters, parsedBody.value)};
}
}
if (list.size != 1) {
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected 1 body"),
NULL};
}
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
memcpy(parsedValue, darray_get(&list, 0), sizeof(ParsedValue));
darray_free(&list, NULL);
return (ParsedValueReturn){no_err, parsedValue};
}

View File

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

View File

@@ -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;
} }
} }

View File

@@ -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
View File

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

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

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

View File

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

View File

@@ -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;
}

View File

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

View File

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

View File

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

View File

@@ -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};
if (CStackFrame) { for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
return runtime(new_stackFrame.translated, new_stackFrame.state, new_stackFrame.stack); new_stackFrame.state.registers[i] = NULL;
} else {
if (((*state->currentStackFramePointer)->depth + 1) % STACKFRAME_CHUNKS ==
0) {
*state->currentStackFramePointer =
ar_alloc(sizeof(StackFrame) * STACKFRAME_CHUNKS);
} else {
*state->currentStackFramePointer = *state->currentStackFramePointer + 1;
} }
**state->currentStackFramePointer = new_stackFrame; if (CStackFrame) {
runtime(new_stackFrame.translated, new_stackFrame.state,
new_stackFrame.stack, err);
state->registers[0] = new_stackFrame.state.registers[0];
} else {
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
*currentStackFrame = new_stackFrame;
*state->currentStackFramePointer = currentStackFrame;
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);
} }

View File

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

View File

@@ -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);
uint64_t hash = runtime_hash(data, length, prehash);
ArgonObject *exists = hashmap_lookup_GC(stack->scope, hash); 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);
} }

View File

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

View File

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

View File

@@ -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,13 +21,21 @@ 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);

View 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;
}

View 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

View File

@@ -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;
} }

View File

@@ -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,20 +84,58 @@ 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(
0, 0, 0, "", "Runtime Error",
"__add__ cannot perform addition between a number and %.*s", "__add__ cannot perform addition between a number and %.*s",
type_name->value.as_str.length, type_name->value.as_str->length, type_name->value.as_str->data);
type_name->value.as_str.data);
return ARGON_NULL; 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) ||
(a < 0 && b < 0 && a < INT64_MIN - b);
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_t r;
mpq_init(r); mpq_init(r);
mpq_add(r, *argv[0]->value.as_number, *argv[1]->value.as_number); mpq_add(r, *argv[0]->value.as_number->n.mpq,
*argv[1]->value.as_number->n.mpq);
ArgonObject *result = new_number_object(r); ArgonObject *result = new_number_object(r);
mpq_clear(r); mpq_clear(r);
return result; 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,
@@ -109,21 +146,189 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
"__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(
0, 0, 0, "", "Runtime Error",
"__subtract__ cannot perform subtraction between number and %.*s", "__subtract__ cannot perform subtraction between number and %.*s",
type_name->value.as_str.length, type_name->value.as_str->length, type_name->value.as_str->data);
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);
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;
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); ArgonObject *result = new_number_object(r);
mpq_clear(r); mpq_clear(r);
return result; 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(
ARGON_NUMBER_TYPE, __new__,
create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__)); create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__));
add_field( add_builtin_field(
ARGON_NUMBER_TYPE, "__number__", 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];
}
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
object->value.as_number = ar_alloc(sizeof(struct as_number));
object->type = TYPE_NUMBER;
if (d == 1) {
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_t r;
mpq_init(r); mpq_init(r);
mpq_set_si(r, n, d); mpq_set_si(r, n, d);
object->type = TYPE_NUMBER; object->value.as_number->n.mpq = mpq_new_gc_from(r);
object->value.as_number = mpq_new_gc_from(r); object->as_bool = n != 0;
mpq_clear(r); 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);
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->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 {
mpq_t r; mpq_t r;
mpq_init(r); mpq_init(r);
mpq_set_d(r, d); mpq_set_d(r, d);
object->type = TYPE_NUMBER; object->value.as_number->n.mpq = mpq_new_gc_from(r);
object->value.as_number = mpq_new_gc_from(r); object->as_bool = d != 0;
mpq_clear(r); 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;

View File

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

View File

@@ -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,
disable_method_wrapper);
}
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
ArgonObject *binding_object) { ArgonObject *binding_object) {
return get_field_for_class_l(target, name, strlen(name), binding_object); 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;
}
inline ArgonObject *get_builtin_field(ArgonObject *target,
built_in_fields field) {
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);
} }

View File

@@ -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 *get_field_l(ArgonObject *target, char *name, size_t length,
bool recursive, bool disable_method_wrapper);
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
ArgonObject *binding_object); ArgonObject *binding_object);
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive, ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash,
size_t length, bool recursive,
bool disable_method_wrapper); bool disable_method_wrapper);
ArgonObject *get_builtin_field_for_class(ArgonObject *target,
built_in_fields field,
ArgonObject *binding_object);
ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field);
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

View File

@@ -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);
} }

View File

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

View File

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

View File

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

321
src/shell.c Normal file
View File

@@ -0,0 +1,321 @@
/*
* 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;
}
typedef long ssize_t;
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
View 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

View File

@@ -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);

View 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;
}

View 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

View File

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

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 =
checked_malloc(operation->to_operate_on.size * sizeof(size_t));
uint8_t registerA = translated->registerAssignment++;
set_registers(translated, translated->registerAssignment);
uint64_t first = 0;
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
uint64_t position = translate_parsed(
translated, darray_get(&operation->to_operate_on, i), err);
if (i == 0)
first = position;
if (err->exists) {
free(jump_to_if_false);
return first;
}
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, registerA);
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);
if (err->exists)
return first;
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, registerB);
switch (operation->operation) { switch (operation->operation) {
case TOKEN_PLUS:; case TOKEN_PLUS:;
first = push_instruction_byte(translated, OP_LOAD_ADDITION_FUNCTION); push_instruction_byte(translated, OP_ADDITION);
break; break;
case TOKEN_MINUS: case TOKEN_MINUS:;
first = push_instruction_byte(translated, OP_LOAD_SUBTRACTION_FUNCTION); 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; break;
default: default:
*err = create_err(operation->line, operation->column, operation->length, *err = create_err(operation->line, operation->column, operation->length,
translated->path, "Syntax Error", "unknown operation"); translated->path, "Syntax Error", "unknown operation");
return 0; return 0;
} }
push_instruction_byte(translated, OP_INIT_CALL); push_instruction_byte(translated, registerA);
push_instruction_code(translated, operation->to_operate_on.size); push_instruction_byte(translated, registerB);
push_instruction_byte(
for (size_t i = 0; i < operation->to_operate_on.size; i++) { translated, operation->to_operate_on.size - 1 == i ? 0 : registerA);
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
push_instruction_byte(translated, OP_INSERT_ARG);
push_instruction_code(translated, i);
} }
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;
} }

View File

@@ -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;
} }

View File

@@ -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);

View 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;
}

View 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
View File

@@ -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
View File

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

View File

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

View File

@@ -0,0 +1 @@
term.log(()=10)

1
tests/env.ar Normal file
View File

@@ -0,0 +1 @@
term.log("hello,", env.USER+'.', 'how is', env.XDG_SESSION_TYPE+'?')

10
tests/intergral.ar Normal file
View 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
View File

@@ -0,0 +1,4 @@
term.log(global)
let i = 1e8
while (i) do
i=i-1

3
tests/iteration-test.py Normal file
View File

@@ -0,0 +1,3 @@
i = 1000000
while i:
i=i-1

View 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
View 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