Compare commits
48 Commits
prerelease
...
v1.0.0-jen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e21a7f11c | ||
|
|
01c89f082c | ||
|
|
b7bfbf5596 | ||
|
|
725413ed83 | ||
|
|
5c3e25d97c | ||
|
|
d7f5e4744b | ||
|
|
12cef9103c | ||
|
|
21bfc71250 | ||
|
|
06da01c119 | ||
|
|
5741fb4185 | ||
|
|
7d272a2f4d | ||
|
|
34a083a2a2 | ||
|
|
eb38da212d | ||
|
|
72eca4a15f | ||
|
|
66c0db52e8 | ||
|
|
c94e8a227d | ||
|
|
4bba257728 | ||
|
|
f5ccb2368c | ||
|
|
2d988a5120 | ||
|
|
3d92071d0a | ||
|
|
357c8745a4 | ||
|
|
4101144e26 | ||
|
|
6a32c4721c | ||
|
|
6de89ebb2f | ||
|
|
4d4749c65e | ||
|
|
916d94b32b | ||
| e3108b2606 | |||
| f3912ae49f | |||
|
|
9de85f3b72 | ||
|
|
41a6fb17da | ||
|
|
7a48771976 | ||
|
|
89abf4e036 | ||
|
|
df409dd3f6 | ||
|
|
646938ea79 | ||
|
|
9befc3760a | ||
|
|
3d2ba09518 | ||
| 94b86fc416 | |||
|
|
0a2aa7369f | ||
|
|
0b594d7882 | ||
|
|
c0ba18c37e | ||
|
|
608fd86003 | ||
|
|
434b0ed99e | ||
|
|
bfaf8df0d0 | ||
|
|
3e3df5595e | ||
|
|
51c6bdcea9 | ||
|
|
dd3b3b936d | ||
|
|
b6714b390a | ||
|
|
a9b1d23f79 |
238
.github/workflows/release.yml
vendored
238
.github/workflows/release.yml
vendored
@@ -1,238 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2025 William Bell
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*' # Any tag
|
||||
|
||||
jobs:
|
||||
build-linux-x86_64:
|
||||
runs-on: ubuntu-latest # build both architectures
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install build tools
|
||||
run: sudo apt-get update && sudo apt-get install -y flex bison
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Conan
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install conan
|
||||
conan profile detect
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
conan install . --build=missing
|
||||
conan build .
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
TAG=${GITHUB_REF##refs/tags/}
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
ARCH=$(uname -m)
|
||||
FOLDER="chloride-$TAG-$OS-$ARCH"
|
||||
TAR="$FOLDER.tar.gz"
|
||||
mv build/bin "$FOLDER"
|
||||
cp LICENSE.txt "$FOLDER"
|
||||
tar -czf "$TAR" "$FOLDER"
|
||||
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-x86_64-artifact
|
||||
path: ${{ env.TAR_NAME }}
|
||||
build-linux-arm64:
|
||||
runs-on: ubuntu-22.04-arm # build both architectures
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install build tools
|
||||
run: sudo apt-get update && sudo apt-get install -y flex bison
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Conan
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install conan
|
||||
conan profile detect
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
conan install . --build=missing
|
||||
conan build .
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
TAG=${GITHUB_REF##refs/tags/}
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
ARCH=$(uname -m)
|
||||
FOLDER="chloride-$TAG-$OS-$ARCH"
|
||||
TAR="$FOLDER.tar.gz"
|
||||
mv build/bin "$FOLDER"
|
||||
cp LICENSE.txt "$FOLDER"
|
||||
tar -czf "$TAR" "$FOLDER"
|
||||
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-arm64-artifact
|
||||
path: ${{ env.TAR_NAME }}
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, arm64] # build both architectures
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install build tools
|
||||
run: brew install flex bison
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Install Conan
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install conan
|
||||
if [ "${{ matrix.arch }}" = "x86_64" ] && [ "$(uname -m)" = "arm64" ]; then
|
||||
arch -x86_64 conan profile detect
|
||||
else
|
||||
conan profile detect
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
BUILD_DIR="build_${{ matrix.arch }}"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Use Rosetta for x86_64 builds on Apple Silicon
|
||||
if [ "${{ matrix.arch }}" = "x86_64" ] && [ "$(uname -m)" = "arm64" ]; then
|
||||
arch -x86_64 bash -c "
|
||||
export CMAKE_OSX_ARCHITECTURES=x86_64
|
||||
conan install .. --build=missing
|
||||
conan build ..
|
||||
"
|
||||
else
|
||||
export CMAKE_OSX_ARCHITECTURES="${{ matrix.arch }}"
|
||||
conan install .. --build=missing
|
||||
conan build ..
|
||||
fi
|
||||
|
||||
cd ..
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
TAG=${GITHUB_REF##refs/tags/}
|
||||
OS="macos"
|
||||
ARCH="${{ matrix.arch }}"
|
||||
FOLDER="chloride-$TAG-$OS-$ARCH"
|
||||
TAR="$FOLDER.tar.gz"
|
||||
mv build/bin "$FOLDER"
|
||||
cp LICENSE.txt "$FOLDER"
|
||||
tar -czf "$TAR" "$FOLDER"
|
||||
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-${{ matrix.arch }}-artifact
|
||||
path: ${{ env.TAR_NAME }}
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: >
|
||||
base-devel
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-make
|
||||
mingw-w64-x86_64-cmake
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-python-pip
|
||||
msys/flex
|
||||
|
||||
- name: Install Conan
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install conan
|
||||
conan profile detect
|
||||
|
||||
- name: Build Project
|
||||
run: |
|
||||
conan install . --profile windows-profile.txt --build=missing
|
||||
conan build . --profile windows-profile.txt
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
TAG=${GITHUB_REF##refs/tags/}
|
||||
OS="windows"
|
||||
ARCH=$(uname -m)
|
||||
FOLDER="chloride-$TAG-$OS-$ARCH"
|
||||
TAR="$FOLDER.tar.gz"
|
||||
mv build/bin "$FOLDER"
|
||||
cp LICENSE.txt "$FOLDER"
|
||||
tar -czf "$TAR" "$FOLDER"
|
||||
echo "TAR_NAME=$TAR" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-artifact
|
||||
path: ${{ env.TAR_NAME }}
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-linux-x86_64, build-linux-arm64, build-macos, build-windows]
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./artifacts
|
||||
merge-multiple: true
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ github.ref_name }}
|
||||
name: Release ${{ github.ref_name }}
|
||||
body: Automated release based on tag ${{ github.ref_name }}
|
||||
draft: false
|
||||
prerelease: ${{ startsWith(github.ref_name, 'prerelease-') }}
|
||||
artifacts: "./artifacts/*"
|
||||
170
Jenkinsfile
vendored
Normal file
170
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
pipeline {
|
||||
agent any
|
||||
environment {
|
||||
GITEA_URL = 'https://git.wbell.dev'
|
||||
GITEA_REPO = 'Open-Argon/Chloride'
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
script {
|
||||
// Detect if this is a tag build via Jenkins-supplied vars
|
||||
if (env.GIT_TAG) {
|
||||
echo "Checking out tag: ${env.GIT_TAG}"
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: [[name: "refs/tags/${env.GIT_TAG}"]],
|
||||
userRemoteConfigs: [[url: scm.userRemoteConfigs[0].url]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [
|
||||
[$class: 'SubmoduleUpdate', recursiveSubmodules: true]
|
||||
]
|
||||
])
|
||||
} else {
|
||||
echo "Checking out normal branch"
|
||||
checkout scm
|
||||
}
|
||||
|
||||
// update submodules
|
||||
sh '''
|
||||
git fetch --tags
|
||||
latest_tag=$(git describe --tags --abbrev=0)
|
||||
git checkout tags/$latest_tag
|
||||
'''
|
||||
sh 'git submodule update --init --recursive'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stage('Detect Tag') {
|
||||
steps {
|
||||
script {
|
||||
echo "REF from Gitea: ${env.GITEA_REF}"
|
||||
echo "GIT_BRANCH: ${env.GIT_BRANCH}"
|
||||
echo "GIT_TAG: ${env.GIT_TAG}"
|
||||
|
||||
def ref = sh(script: "git rev-parse --symbolic-full-name HEAD", returnStdout: true).trim()
|
||||
if (ref.startsWith('refs/tags/')) {
|
||||
def tag = ref.replace('refs/tags/', '')
|
||||
echo "Tag detected: ${tag}"
|
||||
|
||||
if (tag.toLowerCase().contains('unsable')) {
|
||||
echo "Tag contains 'unsable' → marking build UNSTABLE"
|
||||
currentBuild.result = 'UNSTABLE'
|
||||
}
|
||||
|
||||
// Expose for other stages
|
||||
env.TAG_NAME = tag
|
||||
} else {
|
||||
// Normal branch push = DEV build
|
||||
def branchName = ref.replace("refs/heads/", "")
|
||||
echo "Regular branch build: ${branchName}"
|
||||
|
||||
// Mark display name as a dev build
|
||||
currentBuild.displayName = "#${env.BUILD_NUMBER} DEV-${branchName}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Setup Conan') {
|
||||
steps {
|
||||
sh '''
|
||||
apt update
|
||||
apt install -y cmake flex python3 python3-pip python3-venv
|
||||
python3 -m venv /tmp/venv
|
||||
. /tmp/venv/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install conan
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Setup Conan Profile') {
|
||||
steps {
|
||||
sh '''
|
||||
. /tmp/venv/bin/activate
|
||||
rm -rf ~/.conan2
|
||||
conan profile detect
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Install Dependencies') {
|
||||
steps {
|
||||
sh '''
|
||||
. /tmp/venv/bin/activate
|
||||
conan install . --build=missing
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build Project') {
|
||||
steps {
|
||||
sh '''
|
||||
. /tmp/venv/bin/activate
|
||||
conan build .
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stage('Archive Build Artifacts') {
|
||||
steps {
|
||||
script {
|
||||
// Determine platform
|
||||
def os = sh(returnStdout: true, script: 'uname -s').trim().toLowerCase()
|
||||
def arch = sh(returnStdout: true, script: 'uname -m').trim().toLowerCase()
|
||||
|
||||
// Determine version (tag or "dev")
|
||||
def version = env.TAG_NAME ?: "dev"
|
||||
|
||||
// Construct file name
|
||||
env.OUTPUT_FILE = "chloride-${version}-${os}-${arch}.tar.gz"
|
||||
|
||||
echo "Packaging as: ${env.OUTPUT_FILE}"
|
||||
}
|
||||
|
||||
sh '''
|
||||
# Ensure LICENSE.txt is in the output directory
|
||||
cp LICENSE.txt build/bin/
|
||||
|
||||
# Create tarball with auto-generated name
|
||||
tar -czf "$OUTPUT_FILE" -C build/bin .
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: "${env.OUTPUT_FILE}", allowEmptyArchive: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
// Automatically detects full ref name
|
||||
def ref = sh(script: "git rev-parse --symbolic-full-name HEAD", returnStdout: true).trim()
|
||||
|
||||
if (ref.startsWith("refs/tags/")) {
|
||||
// Extract tag name
|
||||
def tag = ref.replace("refs/tags/", "")
|
||||
echo "Detected tag: ${tag}"
|
||||
|
||||
if (tag.toLowerCase().contains("unstable")) {
|
||||
echo "Unstable tag detected"
|
||||
currentBuild.result = "UNSTABLE"
|
||||
} else {
|
||||
echo "Stable tagged build"
|
||||
currentBuild.description = "Stable"
|
||||
currentBuild.result = "SUCCESS"
|
||||
}
|
||||
|
||||
} else {
|
||||
currentBuild.result = "UNSTABLE"
|
||||
echo "Regular commit → marking as dev build"
|
||||
currentBuild.description = "Dev Build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
README.md
77
README.md
@@ -4,6 +4,79 @@ SPDX-FileCopyrightText: 2025 William Bell
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
|
||||
# Chloride
|
||||
<div align="center">
|
||||
<p>
|
||||
<img width="150" src="logo/logo.png">
|
||||
</p>
|
||||
<h1>Chloride</h1>
|
||||
</div>
|
||||
|
||||
An Argon interpreter written in C
|
||||
Chloride is the new C-based interpreter for the Argon programming language.
|
||||
It is designed as a drop-in replacement for the older Go implementation (argon-v3), while introducing a more efficient runtime and a cleaner, more consistent object model.
|
||||
|
||||
## Build
|
||||
|
||||
Currently, builds are only being made for linux x86_64 at [the projects Jenklins instance](https://jenkins.wbell.dev/job/chloride/).
|
||||
|
||||
If this does not satify your requirements, feel free to build for your platform. the dependancies are `conan`, `flex`, `cmake` and `gcc`.
|
||||
|
||||
install using conan.
|
||||
```
|
||||
conan install . --build=missing
|
||||
```
|
||||
|
||||
and finally build using conan.
|
||||
```
|
||||
conan build .
|
||||
```
|
||||
|
||||
the final build can be found in `build/bin`.
|
||||
|
||||
## Overview
|
||||
|
||||
Chloride aims to remain as interchangeable with argon-v3 as possible.
|
||||
Most existing Argon code should run with minimal or no changes, and backwards compatibility is an ongoing priority.
|
||||
Where behaviour differs, the goal is for those differences to be predictable and well-defined rather than accidental quirks.
|
||||
|
||||
This interpreter replaces argon-v3's AST-walking runtime with a proper bytecode compiler, caching system, and virtual machine.
|
||||
The result is a more consistent execution model, lower memory usage, and improved overall performance, even though speed is not the sole focus of the project.
|
||||
|
||||
## Key Improvements Over argon-v3
|
||||
|
||||
- **Bytecode + VM architecture**
|
||||
Chloride compiles source code into bytecode and executes it through a dedicated virtual machine.
|
||||
The previous interpreter evaluated the AST directly at runtime, which limited performance and made optimisations difficult.
|
||||
|
||||
- **Reduced memory usage and CPU overhead**
|
||||
Chloride is written in C with an emphasis on minimal allocations, predictable lifetimes, and efficient object handling.
|
||||
|
||||
- **Unified object model**
|
||||
In contrast to argon-v3, where some values (such as numbers) were not objects, Chloride treats every value as a first-class object.
|
||||
This simplifies the runtime and ensures a more consistent behaviour across all types.
|
||||
|
||||
- **Proper class and inheritance system**
|
||||
Classes in Chloride are real objects, supporting inheritance and introspection in a clean, well-defined manner.
|
||||
The old interpreter treated classes as a special-case construct, which restricted the language's expressiveness.
|
||||
|
||||
- **Backwards compatibility focus**
|
||||
Chloride aims to match argon-v3’s behaviour closely enough that most existing Argon programs run unchanged.
|
||||
Compatibility fixes and behavioural parity are treated as long-term goals.
|
||||
|
||||
## Project Goals
|
||||
|
||||
- Maintain high compatibility with argon-v3.
|
||||
- Minimise memory usage and improve runtime efficiency.
|
||||
- Provide a stable, maintainable interpreter core.
|
||||
- Keep the implementation straightforward so that future language features can be built cleanly on top of it.
|
||||
- Serve as the reference interpreter for Argon going forward.
|
||||
|
||||
|
||||
## Project Status
|
||||
|
||||
Chloride is still under active development.
|
||||
The object model is largely complete, but several core language features are missing or experimental. Basic control flow constructs such as for loops are not implemented yet, partly because the older syntax was confusing and may be replaced with something clearer. While backwards compatibility is a goal, perfect compatibility is unlikely, especially where new syntax or improved semantics resolve long-standing issues in argon-v3.
|
||||
|
||||
The interpreter currently contains known performance issues and occasional segmentation faults, and part of the development process is identifying and removing these. The intention is to stabilise the runtime, finalise the syntax, and avoid any further major redesigns. The hope is that Chloride becomes both the long-term Argon interpreter and the last large rewrite the language needs.
|
||||
|
||||
# Licence
|
||||
GNU General Public License v3.0
|
||||
|
||||
@@ -16,12 +16,15 @@ class ArgonConan(ConanFile):
|
||||
# Remove tool_requires, no flex from Conan
|
||||
requires = [
|
||||
"gmp/6.3.0",
|
||||
"bdwgc/8.2.8"
|
||||
"bdwgc/8.2.6"
|
||||
]
|
||||
|
||||
default_options = {
|
||||
"gmp/*:shared": False,
|
||||
"bdwgc/*:shared": False
|
||||
"bdwgc/*:shared": False,
|
||||
"bdwgc/*:parallel_mark": False,
|
||||
"bdwgc/*:threads": True,
|
||||
"bdwgc/*:disable_debug": True,
|
||||
}
|
||||
|
||||
def layout(self):
|
||||
|
||||
BIN
logo/logo.png
Normal file
BIN
logo/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
84
logo/logo.svg
Normal file
84
logo/logo.svg
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:export-filename="logo.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="1.6199927"
|
||||
inkscape:cx="166.66742"
|
||||
inkscape:cy="208.33427"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1414"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<rect
|
||||
x="96.463768"
|
||||
y="150.58824"
|
||||
width="287.20887"
|
||||
height="242.68713"
|
||||
id="rect1" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#555555;fill-opacity:1"
|
||||
id="path7"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:sides="17"
|
||||
sodipodi:cx="150.15175"
|
||||
sodipodi:cy="58.052856"
|
||||
sodipodi:r1="46.661324"
|
||||
sodipodi:r2="37.32906"
|
||||
sodipodi:arg1="0.30400094"
|
||||
sodipodi:arg2="0.48880051"
|
||||
inkscape:rounded="0.4"
|
||||
inkscape:randomized="2.7755576e-17"
|
||||
d="m 194.67349,72.020461 c -1.44879,4.618019 -9.29136,-0.712277 -11.56404,3.560897 -2.27268,4.273175 6.53108,7.796197 3.5119,11.579008 -3.01918,3.782812 -8.40662,-4.020601 -12.06948,-0.856972 -3.66286,3.163629 3.27373,9.629034 -0.90807,12.065747 -4.18181,2.436719 -6.38654,-6.785922 -10.94489,-5.159103 -4.55835,1.626819 -0.42574,10.161412 -5.2054,10.922942 -4.77966,0.76152 -3.50391,-8.634768 -8.34212,-8.76447 -4.83821,-0.129703 -4.06772,9.32144 -8.79971,8.30493 -4.732,-1.01651 -0.14806,-9.317437 -4.61271,-11.186144 -4.46464,-1.868708 -7.16032,7.222558 -11.20557,4.565293 -4.04525,-2.657264 3.22778,-8.741737 -0.26032,-12.097069 -3.4881,-3.355333 -9.28589,4.148226 -12.09806,0.209088 -2.81217,-3.939138 6.1677,-6.985416 4.12723,-11.374218 -2.04047,-4.388801 -10.15735,0.513654 -11.35664,-4.175355 -1.19929,-4.689009 8.27463,-4.285677 7.95737,-9.115215 -0.31727,-4.829539 -9.65701,-3.190291 -9.08144,-7.995895 0.57556,-4.805603 9.26403,-1.007133 10.71282,-5.625152 1.44879,-4.61802 -7.85242,-6.463369 -5.57974,-10.736544 2.27268,-4.273174 9.00227,2.407431 12.02145,-1.375381 3.01917,-3.782811 -4.98733,-8.863533 -1.32447,-12.027163 3.66286,-3.163629 7.5247,5.496857 11.70651,3.060143 4.18181,-2.436714 -1.44866,-10.066629 3.10969,-11.693447 4.55835,-1.626819 5.03088,7.843901 9.81054,7.082377 4.77966,-0.761525 2.28565,-9.91017 7.12386,-9.780467 4.83821,0.129703 1.85761,9.131584 6.58961,10.148098 4.73199,1.016513 5.71126,-8.415288 10.17591,-6.546581 4.46464,1.868707 -1.56654,9.185997 2.47871,11.843261 4.04525,2.657265 8.36555,-5.783874 11.85365,-2.428541 3.4881,3.355332 -4.77911,7.999788 -1.96695,11.938927 2.81217,3.939138 9.89002,-2.371317 11.93049,2.017485 2.04047,4.388801 -7.34625,5.733164 -6.14696,10.422174 1.19929,4.689009 10.07879,1.3615 10.39605,6.191039 0.31727,4.829538 -8.92123,2.692245 -9.49679,7.497849 -0.57556,4.805603 8.90636,4.910439 7.45757,9.528459 z"
|
||||
inkscape:transform-center-x="1.5847721"
|
||||
inkscape:transform-center-y="-0.51694771"
|
||||
transform="matrix(5.4829104,-0.55336355,0.55336355,5.4829104,-597.77534,21.197933)" />
|
||||
<path
|
||||
style="font-weight:bold;font-size:96px;font-family:'TeX Gyre Heros';-inkscape-font-specification:'TeX Gyre Heros, Bold';white-space:pre;inline-size:117.996;fill:#a9bacd"
|
||||
d="m 231.18969,194.33982 h -14.016 c -0.864,8.928 -6.528,12.96 -15.456,12.96 -11.136,0 -17.664,-8.544 -17.664,-23.808 0,-15.456 6.816,-24.096 18.144,-24.096 7.776,0 12.864,3.552 14.976,12.576 h 13.728 c -1.248,-16.128 -13.44,-24.864 -29.184,-24.864 -19.776,0 -32.064,13.536 -32.064,36.192 0,22.464 12.192,36.096 31.68,36.096 17.376,0 28.992,-9.024 29.856,-25.056 z m 23.42401,23.904 v -69.984 h -13.44 v 69.984 z"
|
||||
id="text2"
|
||||
transform="matrix(4.4012947,0,0,3.7064713,-720.43857,-423.2176)"
|
||||
aria-label="Cl" />
|
||||
<rect
|
||||
style="fill:#a9bacd;fill-opacity:1;stroke-width:0.783784"
|
||||
id="rect4"
|
||||
width="43.448219"
|
||||
height="12.658142"
|
||||
x="421.52911"
|
||||
y="134.00171"
|
||||
sodipodi:insensitive="true" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -16,11 +16,11 @@ typedef enum {
|
||||
__base__,
|
||||
__class__,
|
||||
__name__,
|
||||
__binding__,
|
||||
__function__,
|
||||
|
||||
BUILT_IN_ARRAY_COUNT,
|
||||
|
||||
__binding__,
|
||||
__function__,
|
||||
__add__,
|
||||
__string__,
|
||||
__subtract__,
|
||||
@@ -29,13 +29,15 @@ typedef enum {
|
||||
__new__,
|
||||
__init__,
|
||||
__boolean__,
|
||||
__get_attr__,
|
||||
__getattr__,
|
||||
field__address,
|
||||
__call__,
|
||||
__number__,
|
||||
field_length,
|
||||
__getattribute__,
|
||||
__set_attr__,
|
||||
__setattr__,
|
||||
__getitem__,
|
||||
__setitem__,
|
||||
__hash__,
|
||||
__repr__,
|
||||
|
||||
|
||||
45
src/import.c
45
src/import.c
@@ -43,6 +43,15 @@ static inline uint64_t htole64(uint64_t x) { return x; }
|
||||
#elif defined(__linux__)
|
||||
#include <endian.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int is_regular_file(const char *path) {
|
||||
struct stat path_stat;
|
||||
stat(path, &path_stat);
|
||||
return S_ISREG(path_stat.st_mode);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||
@@ -93,11 +102,11 @@ 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
|
||||
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,
|
||||
@@ -285,7 +294,6 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
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'",
|
||||
@@ -400,7 +408,8 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
Translated gc_translated = {
|
||||
translated.registerCount, translated.registerAssignment, NULL, {}, {},
|
||||
translated.path};
|
||||
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity);
|
||||
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity +
|
||||
translated.constants.capacity);
|
||||
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
||||
translated.bytecode.capacity);
|
||||
gc_translated.bytecode.element_size = translated.bytecode.element_size;
|
||||
@@ -408,7 +417,8 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
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);
|
||||
gc_translated.constants.data =
|
||||
gc_translated.bytecode.data + translated.bytecode.capacity;
|
||||
memcpy(gc_translated.constants.data, translated.constants.data,
|
||||
translated.constants.capacity);
|
||||
gc_translated.constants.size = translated.constants.size;
|
||||
@@ -422,8 +432,8 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
}
|
||||
|
||||
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"};
|
||||
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;
|
||||
@@ -431,8 +441,9 @@ 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));
|
||||
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)) {
|
||||
@@ -445,9 +456,10 @@ Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||
path_relative);
|
||||
return NULL;
|
||||
}
|
||||
if (!importing_hash_table) importing_hash_table = createHashmap();
|
||||
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);
|
||||
hashmap_insert(importing_hash_table, hash, path, (void *)true, 0);
|
||||
Translated translated = load_argon_file(path, err);
|
||||
if (err->exists) {
|
||||
return NULL;
|
||||
@@ -462,8 +474,9 @@ Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||
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(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;
|
||||
}
|
||||
35
src/memory.c
35
src/memory.c
@@ -6,12 +6,11 @@
|
||||
|
||||
#include "memory.h"
|
||||
#include <gc.h>
|
||||
#include <gc/gc.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // for malloc/free (temp arena fallback)
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
void *checked_malloc(size_t size) {
|
||||
void *ptr = malloc(size);
|
||||
@@ -22,14 +21,24 @@ void *checked_malloc(size_t size) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct allocation*memory_allocations = NULL;
|
||||
void *checked_realloc(void *ptr, size_t size) {
|
||||
void *new_ptr = realloc(ptr, size);
|
||||
if (!new_ptr) {
|
||||
fprintf(stderr, "fatal error: failed to allocate %zu bytes\n", size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
struct allocation *memory_allocations = NULL;
|
||||
size_t memory_allocations_size = 0;
|
||||
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void ar_memory_init() {
|
||||
GC_INIT();
|
||||
// memory_allocations_size = 8;
|
||||
// memory_allocations = malloc(memory_allocations_size*sizeof(struct allocation));
|
||||
// memory_allocations = malloc(memory_allocations_size*sizeof(struct
|
||||
// allocation));
|
||||
}
|
||||
|
||||
void ar_memory_shutdown() {
|
||||
@@ -41,9 +50,23 @@ void ar_memory_shutdown() {
|
||||
// free(memory_allocations);
|
||||
}
|
||||
|
||||
void *ar_alloc(size_t size) { return GC_MALLOC(size); }
|
||||
void *ar_alloc(size_t size) {
|
||||
void *ptr = GC_MALLOC(size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "panic: unable to allocate memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *ar_realloc(void *old, size_t size) { return GC_REALLOC(old, size); }
|
||||
void *ar_realloc(void *old, size_t size) {
|
||||
void *ptr = GC_REALLOC(old, size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "panic: unable to allocate memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
||||
GC_finalization_proc *old_fn, void **old_client_data) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdbool.h>
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
|
||||
// GC-managed allocations
|
||||
|
||||
@@ -37,5 +37,6 @@ void ar_memory_init();
|
||||
void ar_memory_shutdown();
|
||||
|
||||
void *checked_malloc(size_t size);
|
||||
void *checked_realloc(void *ptr, size_t size);
|
||||
|
||||
#endif // ARGON_MEMORY_H
|
||||
@@ -15,41 +15,38 @@
|
||||
|
||||
ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
||||
ParsedValue *to_access) {
|
||||
Token *first_token = darray_get(tokens, *index);
|
||||
(*index)++;
|
||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||
if (first_token->type == TOKEN_DOT) {
|
||||
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
||||
parsedAccess->to_access = to_access;
|
||||
parsedAccess->access = NULL;
|
||||
parsedValue->type = AST_ACCESS;
|
||||
parsedValue->data = parsedAccess;
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
Token *token = darray_get(tokens, *index);
|
||||
if (token->type != TOKEN_IDENTIFIER) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||
token->length, file, "Syntax Error",
|
||||
"expected identifier after dot"),
|
||||
NULL};
|
||||
}
|
||||
parsedAccess->line = token->line;
|
||||
parsedAccess->column = token->column;
|
||||
parsedAccess->length = token->length;
|
||||
ParsedValueReturn parsedString = parse_string(token, false);
|
||||
if (parsedString.err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return parsedString;
|
||||
}
|
||||
parsedAccess->access = parsedString.value;
|
||||
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
||||
parsedAccess->to_access = to_access;
|
||||
parsedAccess->access = NULL;
|
||||
parsedValue->type = AST_ACCESS;
|
||||
parsedValue->data = parsedAccess;
|
||||
(*index)++;
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
Token *token = darray_get(tokens, *index);
|
||||
if (token->type != TOKEN_IDENTIFIER) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||
token->length, file, "Syntax Error",
|
||||
"expected identifier after dot"),
|
||||
NULL};
|
||||
}
|
||||
parsedAccess->line = token->line;
|
||||
parsedAccess->column = token->column;
|
||||
parsedAccess->length = token->length;
|
||||
ParsedValueReturn parsedString = parse_string(token, false);
|
||||
if (parsedString.err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return parsedString;
|
||||
}
|
||||
parsedAccess->access = parsedString.value;
|
||||
(*index)++;
|
||||
return (ParsedValueReturn){no_err, parsedValue};
|
||||
}
|
||||
|
||||
@@ -84,12 +84,22 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
(*index)++;
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(assign_to);
|
||||
free(assign_to);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
token = darray_get(tokens, *index);
|
||||
ParsedValueReturn from = parse_token(file, tokens, index, true);
|
||||
if (from.err.exists) {
|
||||
free_parsed(assign_to);
|
||||
free(assign_to);
|
||||
return from;
|
||||
}
|
||||
if (!from.value) {
|
||||
free_parsed(assign_to);
|
||||
free(assign_to);
|
||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||
token->length, file, "Syntax Error",
|
||||
"expected body"),
|
||||
@@ -110,12 +120,6 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||
parsedValue->type = AST_ASSIGN;
|
||||
parsedValue->data = assign;
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
assign->from = from.value;
|
||||
return (ParsedValueReturn){no_err, parsedValue};
|
||||
}
|
||||
|
||||
80
src/parser/assignable/item/item.c
Normal file
80
src/parser/assignable/item/item.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "item.h"
|
||||
#include "../../../lexer/token.h"
|
||||
#include "../../../memory.h"
|
||||
#include "../../parser.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index,
|
||||
ParsedValue *to_access) {
|
||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||
ParsedItemAccess *parsedItemAccess = checked_malloc(sizeof(ParsedItemAccess));
|
||||
parsedItemAccess->to_access = to_access;
|
||||
size_t capacity = 4;
|
||||
parsedItemAccess->items = checked_malloc(capacity * sizeof(ParsedValue *));
|
||||
parsedItemAccess->itemc = 0;
|
||||
parsedValue->type = AST_ITEM_ACCESS;
|
||||
parsedValue->data = parsedItemAccess;
|
||||
Token *token = darray_get(tokens, *index);
|
||||
parsedItemAccess->line = token->line;
|
||||
parsedItemAccess->column = token->column;
|
||||
parsedItemAccess->length = token->length;
|
||||
(*index)++;
|
||||
while (true) {
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
ParsedValueReturn parsedKey = parse_token(file, tokens, index, true);
|
||||
if (parsedKey.err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return parsedKey;
|
||||
}
|
||||
parsedItemAccess->items[parsedItemAccess->itemc++] = parsedKey.value;
|
||||
if (parsedItemAccess->itemc > capacity) {
|
||||
capacity *= 2;
|
||||
parsedItemAccess->items = checked_realloc(
|
||||
parsedItemAccess->items, capacity * sizeof(ParsedValue *));
|
||||
}
|
||||
Token *token = darray_get(tokens, *index);
|
||||
(*index)++;
|
||||
if (token->type == TOKEN_COMMA) {
|
||||
continue;
|
||||
} else if (token->type == TOKEN_RBRACKET) {
|
||||
break;
|
||||
} else {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){
|
||||
create_err(token->line, token->column, token->length, file,
|
||||
"Syntax Error",
|
||||
"expected either a comma or a closing bracket"),
|
||||
NULL};
|
||||
}
|
||||
}
|
||||
return (ParsedValueReturn){no_err, parsedValue};
|
||||
}
|
||||
|
||||
void free_parse_item_access(void *ptr) {
|
||||
ParsedValue *parsedValue = ptr;
|
||||
ParsedItemAccess *parsedItemAccess = parsedValue->data;
|
||||
free_parsed(parsedItemAccess->to_access);
|
||||
free(parsedItemAccess->to_access);
|
||||
for (size_t i = 0; i < parsedItemAccess->itemc; i++) {
|
||||
free_parsed(parsedItemAccess->items[i]);
|
||||
free(parsedItemAccess->items[i]);
|
||||
}
|
||||
free(parsedItemAccess->items);
|
||||
free(parsedItemAccess);
|
||||
}
|
||||
25
src/parser/assignable/item/item.h
Normal file
25
src/parser/assignable/item/item.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ITEM_ACCESS_H
|
||||
#define ITEM_ACCESS_H
|
||||
#include "../../parser.h"
|
||||
#include "../../../lexer/token.h" // for Token
|
||||
typedef struct {
|
||||
ParsedValue *to_access;
|
||||
ParsedValue **items;
|
||||
size_t itemc;
|
||||
size_t line;
|
||||
size_t column;
|
||||
size_t length;
|
||||
} ParsedItemAccess;
|
||||
|
||||
ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index,
|
||||
ParsedValue *to_access);
|
||||
|
||||
void free_parse_item_access(void *ptr);
|
||||
|
||||
#endif // ACCESS_H
|
||||
@@ -47,6 +47,7 @@ ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index) {
|
||||
"Syntax Error", "expected comma"),
|
||||
NULL};
|
||||
}
|
||||
(*index)++;
|
||||
skip_newlines_and_indents(tokens, index);
|
||||
err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "assignable/assign/assign.h"
|
||||
#include "assignable/call/call.h"
|
||||
#include "assignable/identifier/identifier.h"
|
||||
#include "assignable/item/item.h"
|
||||
#include "declaration/declaration.h"
|
||||
#include "dictionary/dictionary.h"
|
||||
#include "dowrap/dowrap.h"
|
||||
@@ -164,9 +165,11 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
|
||||
output = parse_call(file, tokens, index, output.value);
|
||||
break;
|
||||
case TOKEN_DOT:
|
||||
case TOKEN_LBRACKET:
|
||||
output = parse_access(file, tokens, index, output.value);
|
||||
break;
|
||||
case TOKEN_LBRACKET:
|
||||
output = parse_item_access(file, tokens, index, output.value);
|
||||
break;
|
||||
SWITCH_OPERATIONS
|
||||
if (process_operations) {
|
||||
output = parse_operations(file, tokens, index, output.value);
|
||||
@@ -199,7 +202,7 @@ ArErr parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) {
|
||||
if (expecting_new_line) {
|
||||
Token *token = darray_get(tokens, old_index);
|
||||
return create_err(token->line, token->column, token->length, file,
|
||||
"Syntax Error", "expected new line");
|
||||
"Syntax Error", "invalid syntax");
|
||||
}
|
||||
expecting_new_line = true;
|
||||
darray_push(parsed, parsed_code.value);
|
||||
@@ -241,6 +244,9 @@ void free_parsed(void *ptr) {
|
||||
case AST_ACCESS:
|
||||
free_parse_access(parsed);
|
||||
break;
|
||||
case AST_ITEM_ACCESS:
|
||||
free_parse_item_access(parsed);
|
||||
break;
|
||||
case AST_NULL:
|
||||
case AST_BOOLEAN:
|
||||
break;
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef enum {
|
||||
AST_NUMBER,
|
||||
AST_IF,
|
||||
AST_ACCESS,
|
||||
AST_ITEM_ACCESS,
|
||||
AST_CALL,
|
||||
AST_DECLARATION,
|
||||
AST_NULL,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -121,6 +122,7 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
||||
(int)object_name->value.as_str->length,
|
||||
object_name->value.as_str->data,
|
||||
object->value.argon_fn->number_of_parameters, argc);
|
||||
return;
|
||||
}
|
||||
Stack *scope = create_scope(object->value.argon_fn->stack, true);
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
@@ -131,36 +133,58 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
||||
new_string_object(key.data, key.length, 0, hash), value,
|
||||
0);
|
||||
}
|
||||
StackFrame new_stackFrame = {
|
||||
{object->value.argon_fn->translated.registerCount,
|
||||
object->value.argon_fn->translated.registerAssignment,
|
||||
NULL,
|
||||
{object->value.argon_fn->bytecode, sizeof(uint8_t),
|
||||
object->value.argon_fn->bytecode_length,
|
||||
object->value.argon_fn->bytecode_length, false},
|
||||
object->value.argon_fn->translated.constants,
|
||||
object->value.argon_fn->translated.path},
|
||||
{ar_alloc(object->value.argon_fn->translated.registerCount *
|
||||
sizeof(ArgonObject *)),
|
||||
0,
|
||||
object->value.argon_fn->translated.path,
|
||||
NULL,
|
||||
state->currentStackFramePointer,
|
||||
{},
|
||||
{}},
|
||||
scope,
|
||||
*state->currentStackFramePointer,
|
||||
(*state->currentStackFramePointer)->depth + 1};
|
||||
for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
|
||||
new_stackFrame.state.registers[i] = NULL;
|
||||
}
|
||||
if (CStackFrame) {
|
||||
ArgonObject * registers[MAX_REGISTERS]; // fixed on the stack for speed purposes
|
||||
StackFrame new_stackFrame = {
|
||||
{object->value.argon_fn->translated.registerCount,
|
||||
object->value.argon_fn->translated.registerAssignment,
|
||||
NULL,
|
||||
{object->value.argon_fn->bytecode, sizeof(uint8_t),
|
||||
object->value.argon_fn->bytecode_length,
|
||||
object->value.argon_fn->bytecode_length, false},
|
||||
object->value.argon_fn->translated.constants,
|
||||
object->value.argon_fn->translated.path},
|
||||
{registers,
|
||||
0,
|
||||
object->value.argon_fn->translated.path,
|
||||
NULL,
|
||||
state->currentStackFramePointer,
|
||||
{},
|
||||
{}},
|
||||
scope,
|
||||
*state->currentStackFramePointer,
|
||||
(*state->currentStackFramePointer)->depth + 1};
|
||||
for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
|
||||
new_stackFrame.state.registers[i] = NULL;
|
||||
}
|
||||
runtime(new_stackFrame.translated, new_stackFrame.state,
|
||||
new_stackFrame.stack, err);
|
||||
state->registers[0] = new_stackFrame.state.registers[0];
|
||||
} else {
|
||||
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
|
||||
*currentStackFrame = new_stackFrame;
|
||||
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame)+object->value.argon_fn->translated.registerCount *
|
||||
sizeof(ArgonObject *));
|
||||
*currentStackFrame = (StackFrame){
|
||||
{object->value.argon_fn->translated.registerCount,
|
||||
object->value.argon_fn->translated.registerAssignment,
|
||||
NULL,
|
||||
{object->value.argon_fn->bytecode, sizeof(uint8_t),
|
||||
object->value.argon_fn->bytecode_length,
|
||||
object->value.argon_fn->bytecode_length, false},
|
||||
object->value.argon_fn->translated.constants,
|
||||
object->value.argon_fn->translated.path},
|
||||
{(ArgonObject **)((char*)currentStackFrame+sizeof(StackFrame)),
|
||||
0,
|
||||
object->value.argon_fn->translated.path,
|
||||
NULL,
|
||||
state->currentStackFramePointer,
|
||||
{},
|
||||
{}},
|
||||
scope,
|
||||
*state->currentStackFramePointer,
|
||||
(*state->currentStackFramePointer)->depth + 1};
|
||||
for (size_t i = 0; i < (*currentStackFrame).translated.registerCount; i++) {
|
||||
(*currentStackFrame).state.registers[i] = NULL;
|
||||
}
|
||||
*state->currentStackFramePointer = currentStackFrame;
|
||||
if ((*state->currentStackFramePointer)->depth >= 10000) {
|
||||
double logval =
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "darray_armem.h"
|
||||
#include "../../../memory.h"
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#include "hashmap.h"
|
||||
|
||||
#include "../../../memory.h"
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -25,26 +26,48 @@ struct hashmap_GC *createHashmap_GC() {
|
||||
t->inline_count = 0;
|
||||
return t;
|
||||
}
|
||||
void hashmap_GC_to_array(struct hashmap_GC *t, struct node_GC**array,
|
||||
size_t *array_length) {
|
||||
|
||||
static int compare_node_asc(const void *a, const void *b) {
|
||||
const struct node_GC *na = *(const struct node_GC **)a;
|
||||
const struct node_GC *nb = *(const struct node_GC **)b;
|
||||
|
||||
// Ascending order (smallest order first)
|
||||
if (na->order < nb->order)
|
||||
return -1;
|
||||
if (na->order > nb->order)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct node_GC ** hashmap_GC_to_array(struct hashmap_GC *t,
|
||||
size_t *array_length) {
|
||||
size_t array_size = 8;
|
||||
*array_length = 0;
|
||||
*array = ar_alloc(array_size * sizeof(struct node_GC));
|
||||
struct node_GC ** array = ar_alloc(array_size * sizeof(struct node_GC*));
|
||||
|
||||
for (size_t i = 0; i < t->inline_count; i++) {
|
||||
if (*array_length >=array_size) {
|
||||
array_size*=2;
|
||||
*array=ar_realloc(*array, array_size * sizeof(struct node_GC));
|
||||
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];
|
||||
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));
|
||||
struct node_GC *list = t->list[i];
|
||||
struct node_GC *temp = list;
|
||||
while (temp) {
|
||||
if (*array_length >= array_size) {
|
||||
array_size *= 2;
|
||||
array = ar_realloc(array, array_size * sizeof(struct node_GC*));
|
||||
}
|
||||
array[(*array_length)++] = temp;
|
||||
temp = temp->next;
|
||||
}
|
||||
(*array)[(*array_length)++] = *t->list[i];
|
||||
}
|
||||
|
||||
qsort(array, *array_length, sizeof(struct node_GC*), compare_node_asc);
|
||||
return array;
|
||||
}
|
||||
|
||||
void clear_hashmap_GC(struct hashmap_GC *t) {
|
||||
|
||||
@@ -33,8 +33,8 @@ 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);
|
||||
struct node_GC ** hashmap_GC_to_array(struct hashmap_GC *t,
|
||||
size_t *array_length);
|
||||
|
||||
int hashCode_GC(struct hashmap_GC *t, uint64_t hash);
|
||||
|
||||
|
||||
@@ -45,18 +45,20 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
|
||||
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);
|
||||
size_t nodes_length;
|
||||
struct node_GC ** nodes = hashmap_GC_to_array(object->value.as_hashmap, &nodes_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;
|
||||
for (size_t i = 0; i < nodes_length; i++) {
|
||||
struct node_GC *node = nodes[i];
|
||||
ArgonObject *key = node->key;
|
||||
ArgonObject *value = node->val;
|
||||
|
||||
if (!key) { fprintf(stderr, "NULL key at node %zu\n", i); continue; }
|
||||
if (!value) { fprintf(stderr, "NULL value at node %zu\n", i); continue; }
|
||||
|
||||
ArgonObject *string_convert_method = get_builtin_field_for_class(
|
||||
get_builtin_field(key, __class__), __repr__, key);
|
||||
@@ -102,7 +104,7 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
|
||||
string_length += length;
|
||||
}
|
||||
|
||||
if (i != keys_length - 1) {
|
||||
if (i != nodes_length - 1) {
|
||||
char *string_obj = ", ";
|
||||
size_t length = strlen(string_obj);
|
||||
string = realloc(string, string_length + length);
|
||||
@@ -120,14 +122,14 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
|
||||
return result;
|
||||
}
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(size_t argc,
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___getattr__(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);
|
||||
"__getattr__ expects 2 argument, got %" PRIu64, argc);
|
||||
return ARGON_NULL;
|
||||
}
|
||||
ArgonObject *object = argv[0];
|
||||
@@ -146,14 +148,62 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(size_t argc,
|
||||
}
|
||||
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___set_attr__(size_t argc,
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___setattr__(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);
|
||||
"__setattr__ 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;
|
||||
}
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___getitem__(size_t argc,
|
||||
ArgonObject **argv,
|
||||
ArErr *err,
|
||||
RuntimeState *state) {
|
||||
(void)state;
|
||||
if (argc != 2) {
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"__getitem__ 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) {
|
||||
char *object_str = argon_object_to_null_terminated_string(key, err, state);
|
||||
|
||||
*err = create_err(0, 0, 0, NULL, "Attribute Error",
|
||||
"Dictionary has no item '%s'", object_str);
|
||||
return ARGON_NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___setitem__(size_t argc,
|
||||
ArgonObject **argv,
|
||||
ArErr *err,
|
||||
RuntimeState *state) {
|
||||
(void)state;
|
||||
if (argc != 3) {
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"__setitem__ expects 2 argument, got %" PRIu64, argc);
|
||||
return ARGON_NULL;
|
||||
}
|
||||
ArgonObject *object = argv[0];
|
||||
@@ -175,13 +225,21 @@ void create_ARGON_DICTIONARY_TYPE() {
|
||||
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__));
|
||||
ARGON_DICTIONARY_TYPE, __getattr__,
|
||||
create_argon_native_function("__getattr__",
|
||||
create_ARGON_DICTIONARY_TYPE___getattr__));
|
||||
add_builtin_field(
|
||||
ARGON_DICTIONARY_TYPE, __set_attr__,
|
||||
create_argon_native_function("__set_attr__",
|
||||
create_ARGON_DICTIONARY_TYPE___set_attr__));
|
||||
ARGON_DICTIONARY_TYPE, __setattr__,
|
||||
create_argon_native_function("__setattr__",
|
||||
create_ARGON_DICTIONARY_TYPE___setattr__));
|
||||
add_builtin_field(
|
||||
ARGON_DICTIONARY_TYPE, __setitem__,
|
||||
create_argon_native_function("__setitem__",
|
||||
create_ARGON_DICTIONARY_TYPE___setitem__));
|
||||
add_builtin_field(
|
||||
ARGON_DICTIONARY_TYPE, __getitem__,
|
||||
create_argon_native_function("__getitem__",
|
||||
create_ARGON_DICTIONARY_TYPE___getitem__));
|
||||
add_builtin_field(ARGON_DICTIONARY_TYPE, __string__,
|
||||
create_argon_native_function(
|
||||
"__string__", create_ARGON_DICTIONARY_TYPE___string__));
|
||||
|
||||
@@ -32,12 +32,12 @@ void load_argon_function(Translated *translated, RuntimeState *state,
|
||||
add_builtin_field(object, __name__,
|
||||
new_string_object(arena_get(&translated->constants, offset),
|
||||
length, 0, 0));
|
||||
object->value.argon_fn = ar_alloc(sizeof(struct argon_function_struct));
|
||||
object->value.argon_fn->translated = *translated;
|
||||
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 *
|
||||
uint64_t number_of_parameters = pop_bytecode(translated, state);
|
||||
object->value.argon_fn = ar_alloc(sizeof(struct argon_function_struct)+number_of_parameters *
|
||||
sizeof(struct string_struct));
|
||||
object->value.argon_fn->parameters = (struct string_struct*)((char*)object->value.argon_fn+sizeof(struct argon_function_struct));
|
||||
object->value.argon_fn->translated = *translated;
|
||||
object->value.argon_fn->number_of_parameters = number_of_parameters;
|
||||
for (size_t i = 0; i < object->value.argon_fn->number_of_parameters; i++) {
|
||||
offset = pop_bytecode(translated, state);
|
||||
length = pop_bytecode(translated, state);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
ArgonObject *ARGON_NUMBER_TYPE;
|
||||
|
||||
@@ -268,6 +269,64 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline uint64_t mix64(uint64_t x) {
|
||||
x ^= x >> 33;
|
||||
x *= 0xff51afd7ed558ccdULL;
|
||||
x ^= x >> 33;
|
||||
x *= 0xc4ceb9fe1a85ec53ULL;
|
||||
x ^= x >> 33;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint64_t hash_mpz(const mpz_t z) {
|
||||
// Export to raw bytes (big-endian for consistency)
|
||||
size_t count;
|
||||
unsigned char *data = mpz_export(NULL, &count, 1, 1, 1, 0, z);
|
||||
|
||||
// FNV-1a over bytes
|
||||
uint64_t h = 1469598103934665603ULL;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
h ^= data[i];
|
||||
h *= 1099511628211ULL;
|
||||
}
|
||||
|
||||
// Include sign bit
|
||||
if (mpz_sgn(z) < 0)
|
||||
h = ~h;
|
||||
|
||||
// Free the temporary buffer allocated by mpz_export
|
||||
free(data);
|
||||
|
||||
return mix64(h);
|
||||
}
|
||||
|
||||
uint64_t hash_mpq(mpq_t q) {
|
||||
uint64_t h_num = hash_mpz(mpq_numref(q));
|
||||
uint64_t h_den = hash_mpz(mpq_denref(q));
|
||||
|
||||
// Combine using a standard 64-bit hash mix (boost-style)
|
||||
uint64_t h = h_num ^ (h_den + 0x9e3779b97f4a7c15ULL + (h_num << 6) + (h_num >> 2));
|
||||
return mix64(h);
|
||||
}
|
||||
|
||||
ArgonObject *ARGON_NUMBER_TYPE___hash__(size_t argc, ArgonObject **argv,
|
||||
ArErr *err, RuntimeState *state) {
|
||||
(void)state;
|
||||
if (argc != 1) {
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"__hash__ expects 1 arguments, got %" PRIu64, argc);
|
||||
}
|
||||
uint64_t hash;
|
||||
if (argv[0]->value.as_number->is_int64) {
|
||||
hash = mix64(argv[0]->value.as_number->n.i64);
|
||||
} else {
|
||||
hash = hash_mpq(*argv[0]->value.as_number->n.mpq);
|
||||
}
|
||||
return new_number_object_from_int64(hash);
|
||||
}
|
||||
|
||||
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
|
||||
ArErr *err, RuntimeState *state) {
|
||||
(void)state;
|
||||
@@ -497,7 +556,6 @@ 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);
|
||||
@@ -520,6 +578,9 @@ void create_ARGON_NUMBER_TYPE() {
|
||||
add_builtin_field(
|
||||
ARGON_NUMBER_TYPE, __number__,
|
||||
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
|
||||
add_builtin_field(
|
||||
ARGON_NUMBER_TYPE, __hash__,
|
||||
create_argon_native_function("__hash__", ARGON_NUMBER_TYPE___hash__));
|
||||
add_builtin_field(ARGON_NUMBER_TYPE, __boolean__,
|
||||
create_argon_native_function(
|
||||
"__boolean__", ARGON_NUMBER_TYPE___boolean__));
|
||||
|
||||
@@ -35,6 +35,8 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
||||
"__class__",
|
||||
"__name__",
|
||||
"", // above is anything that gets stored in built in slots
|
||||
"__binding__",
|
||||
"__function__",
|
||||
"__add__",
|
||||
"__string__",
|
||||
"__subtract__",
|
||||
@@ -43,15 +45,15 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
||||
"__new__",
|
||||
"__init__",
|
||||
"__boolean__",
|
||||
"__get_attr__",
|
||||
"__binding__",
|
||||
"__function__",
|
||||
"__getattr__",
|
||||
"__getitem__",
|
||||
"address",
|
||||
"__call__",
|
||||
"__number__",
|
||||
"length",
|
||||
"__getattribute__",
|
||||
"__set_attr__",
|
||||
"__setattr__",
|
||||
"__setitem__",
|
||||
"__hash__",
|
||||
"__repr__"};
|
||||
|
||||
@@ -77,9 +79,7 @@ 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;
|
||||
return (int64_t)object;
|
||||
}
|
||||
ArgonObject *hash_result = argon_call(hash_function, 0, NULL, err, state);
|
||||
if (hash_result->type != TYPE_NUMBER ||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
extern ArgonObject *BASE_CLASS;
|
||||
|
||||
extern const char *built_in_field_names[BUILT_IN_FIELDS_COUNT];
|
||||
|
||||
typedef struct ArgonObject ArgonObject;
|
||||
|
||||
ArgonObject *new_class();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "string.h"
|
||||
#include "../../call/call.h"
|
||||
#include "../number/number.h"
|
||||
#include "../object.h"
|
||||
#include <ctype.h>
|
||||
@@ -14,51 +15,58 @@
|
||||
|
||||
ArgonObject *ARGON_STRING_TYPE = NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
// 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++] = '"';
|
||||
size_t j = 0;
|
||||
out[j++] = '"';
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
unsigned char c = (unsigned char)input[i];
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
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));
|
||||
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->value.as_str = ar_alloc(sizeof(struct string_struct));
|
||||
object->value.as_str->data = data;
|
||||
@@ -69,18 +77,40 @@ void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||
object->as_bool = length;
|
||||
}
|
||||
|
||||
ArgonObject *new_string_object_without_memcpy(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 *object = new_instance(ARGON_STRING_TYPE);
|
||||
init_string(object,data,length,prehash,hash);
|
||||
init_string(object, data, length, prehash, hash);
|
||||
return object;
|
||||
}
|
||||
|
||||
ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash,
|
||||
uint64_t hash) {
|
||||
char*data_copy = ar_alloc_atomic(length);
|
||||
char *data_copy = ar_alloc_atomic(length);
|
||||
memcpy(data_copy, data, length);
|
||||
return new_string_object_without_memcpy(data_copy,length, prehash, hash);
|
||||
return new_string_object_without_memcpy(data_copy, length, prehash, hash);
|
||||
}
|
||||
|
||||
char *argon_object_to_null_terminated_string(ArgonObject *object, ArErr *err,
|
||||
RuntimeState *state) {
|
||||
ArgonObject *string_convert_method = get_builtin_field_for_class(
|
||||
get_builtin_field(object, __class__), __repr__, object);
|
||||
|
||||
if (!string_convert_method)
|
||||
return "<object>";
|
||||
|
||||
ArgonObject *string_object =
|
||||
argon_call(string_convert_method, 0, NULL, err, state);
|
||||
if (err->exists)
|
||||
return NULL;
|
||||
|
||||
|
||||
if (string_object->type != TYPE_STRING) return "<object>";
|
||||
|
||||
char *string = ar_alloc(string_object->value.as_str->length+1);
|
||||
string[string_object->value.as_str->length] = '\0';
|
||||
memcpy(string, string_object->value.as_str->data, string_object->value.as_str->length);
|
||||
return string;
|
||||
}
|
||||
|
||||
ArgonObject *new_string_object_null_terminated(char *data) {
|
||||
|
||||
@@ -12,13 +12,17 @@ extern ArgonObject *ARGON_STRING_TYPE;
|
||||
|
||||
char *c_quote_string(const char *input, size_t len);
|
||||
|
||||
void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||
void init_string(ArgonObject *object, char *data, size_t length,
|
||||
uint64_t prehash, uint64_t hash);
|
||||
|
||||
char *argon_object_to_null_terminated_string(ArgonObject *object, ArErr *err,
|
||||
RuntimeState *state);
|
||||
|
||||
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_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
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "objects/term/term.h"
|
||||
#include "objects/type/type.h"
|
||||
#include <fcntl.h>
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
#include <gmp.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
@@ -72,11 +72,11 @@ ArgonObject *BASE_CLASS___getattribute__(size_t argc, ArgonObject **argv,
|
||||
access->value.as_str->length, true, false);
|
||||
if (value)
|
||||
return value;
|
||||
ArgonObject *cls__get_attr__ = get_builtin_field_for_class(
|
||||
get_builtin_field(to_access, __class__), __get_attr__, to_access);
|
||||
if (cls__get_attr__) {
|
||||
ArgonObject *cls__getattr__ = get_builtin_field_for_class(
|
||||
get_builtin_field(to_access, __class__), __getattr__, to_access);
|
||||
if (cls__getattr__) {
|
||||
value =
|
||||
argon_call(cls__get_attr__, 1, (ArgonObject *[]){access}, err, state);
|
||||
argon_call(cls__getattr__, 1, (ArgonObject *[]){access}, err, state);
|
||||
if (err->exists) {
|
||||
return ARGON_NULL;
|
||||
}
|
||||
@@ -100,12 +100,13 @@ ArgonObject *ARGON_ADDITION_FUNCTION(size_t argc, ArgonObject **argv,
|
||||
}
|
||||
ArgonObject *output = argv[0];
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
ArgonObject *object_class = get_builtin_field(output, __class__);
|
||||
ArgonObject *object__add__ = get_builtin_field_for_class(
|
||||
get_builtin_field(output, __class__), __add__, output);
|
||||
object_class, __add__, output);
|
||||
if (!object__add__) {
|
||||
ArgonObject *cls___name__ = get_builtin_field(output, __name__);
|
||||
ArgonObject *cls___name__ = get_builtin_field(object_class, __name__);
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"Object '%.*s' is missing __add__ method",
|
||||
"Object of type '%.*s' is missing __add__ method",
|
||||
(int)cls___name__->value.as_str->length,
|
||||
cls___name__->value.as_str->data);
|
||||
return ARGON_NULL;
|
||||
@@ -126,12 +127,13 @@ ArgonObject *ARGON_SUBTRACTION_FUNCTION(size_t argc, ArgonObject **argv,
|
||||
}
|
||||
ArgonObject *output = argv[0];
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
ArgonObject *object_class = get_builtin_field(output, __class__);
|
||||
ArgonObject *function__subtract__ = get_builtin_field_for_class(
|
||||
get_builtin_field(output, __class__), __subtract__, output);
|
||||
object_class, __subtract__, output);
|
||||
if (!function__subtract__) {
|
||||
ArgonObject *cls___name__ = get_builtin_field(output, __name__);
|
||||
ArgonObject *cls___name__ = get_builtin_field(object_class, __name__);
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"Object '%.*s' is missing __subtract__ method",
|
||||
"Object of type '%.*s' is missing __subtract__ method",
|
||||
(int)cls___name__->value.as_str->length,
|
||||
cls___name__->value.as_str->data);
|
||||
return ARGON_NULL;
|
||||
@@ -152,12 +154,13 @@ ArgonObject *ARGON_MULTIPLY_FUNCTION(size_t argc, ArgonObject **argv,
|
||||
}
|
||||
ArgonObject *output = argv[0];
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
ArgonObject *object_class = get_builtin_field(output, __class__);
|
||||
ArgonObject *function__multiply__ = get_builtin_field_for_class(
|
||||
get_builtin_field(output, __class__), __multiply__, output);
|
||||
object_class, __multiply__, output);
|
||||
if (!function__multiply__) {
|
||||
ArgonObject *cls___name__ = get_builtin_field(output, __name__);
|
||||
ArgonObject *cls___name__ = get_builtin_field(object_class, __name__);
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"Object '%.*s' is missing __multiply__ method",
|
||||
"Object of type '%.*s' is missing __multiply__ method",
|
||||
(int)cls___name__->value.as_str->length,
|
||||
cls___name__->value.as_str->data);
|
||||
return ARGON_NULL;
|
||||
@@ -177,12 +180,13 @@ ArgonObject *ARGON_DIVIDE_FUNCTION(size_t argc, ArgonObject **argv, ArErr *err,
|
||||
}
|
||||
ArgonObject *output = argv[0];
|
||||
for (size_t i = 1; i < argc; i++) {
|
||||
ArgonObject *object_class = get_builtin_field(output, __class__);
|
||||
ArgonObject *function___divide__ = get_builtin_field_for_class(
|
||||
get_builtin_field(output, __class__), __divide__, output);
|
||||
object_class, __divide__, output);
|
||||
if (!function___divide__) {
|
||||
ArgonObject *cls___name__ = get_builtin_field(output, __name__);
|
||||
ArgonObject *cls___name__ = get_builtin_field(object_class, __name__);
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"Object '%.*s' is missing __divide__ method",
|
||||
"Object of type '%.*s' is missing __divide__ method",
|
||||
(int)cls___name__->value.as_str->length,
|
||||
cls___name__->value.as_str->data);
|
||||
return ARGON_NULL;
|
||||
@@ -285,12 +289,12 @@ ArgonObject *BASE_CLASS___init__(size_t argc, ArgonObject **argv, ArErr *err,
|
||||
return ARGON_NULL;
|
||||
}
|
||||
|
||||
ArgonObject *BASE_CLASS___set_attr__(size_t argc, ArgonObject **argv, ArErr *err,
|
||||
ArgonObject *BASE_CLASS___setattr__(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 3 argument, got %" PRIu64, argc);
|
||||
"__setattr__ expects 3 argument, got %" PRIu64, argc);
|
||||
}
|
||||
if (!argv[1]->value.as_str->hash)
|
||||
argv[1]->value.as_str->hash =
|
||||
@@ -615,7 +619,6 @@ void bootstrap_types() {
|
||||
add_builtin_field(ARGON_METHOD_TYPE, __base__, BASE_CLASS);
|
||||
add_builtin_field(ARGON_METHOD_TYPE, __name__,
|
||||
new_string_object_null_terminated("method"));
|
||||
create_ARGON_NUMBER_TYPE();
|
||||
|
||||
add_builtin_field(
|
||||
BASE_CLASS, __new__,
|
||||
@@ -692,12 +695,14 @@ void bootstrap_types() {
|
||||
create_argon_native_function("__getattribute__",
|
||||
BASE_CLASS___getattribute__));
|
||||
add_builtin_field(
|
||||
BASE_CLASS, __set_attr__,
|
||||
create_argon_native_function("__set_attr__", BASE_CLASS___set_attr__));
|
||||
BASE_CLASS, __setattr__,
|
||||
create_argon_native_function("__setattr__", BASE_CLASS___setattr__));
|
||||
create_ARGON_DICTIONARY_TYPE();
|
||||
create_ARGON_NUMBER_TYPE();
|
||||
}
|
||||
|
||||
void add_to_hashmap(struct hashmap_GC *hashmap, char *name, ArgonObject *value) {
|
||||
void add_to_hashmap(struct hashmap_GC *hashmap, char *name,
|
||||
ArgonObject *value) {
|
||||
size_t length = strlen(name);
|
||||
uint64_t hash = siphash64_bytes(name, length, siphash_key);
|
||||
ArgonObject *key = new_string_object(name, length, 0, hash);
|
||||
@@ -719,51 +724,53 @@ void bootstrap_globals() {
|
||||
|
||||
struct hashmap_GC *argon_term = createHashmap_GC();
|
||||
add_to_hashmap(argon_term, "log",
|
||||
create_argon_native_function("log", term_log));
|
||||
create_argon_native_function("log", term_log));
|
||||
add_to_scope(Global_Scope, "term", create_dictionary(argon_term));
|
||||
|
||||
|
||||
struct hashmap_GC *environment_variables = createHashmap_GC();
|
||||
#if defined(_WIN32)
|
||||
// Windows: use WinAPI
|
||||
LPCH env = GetEnvironmentStringsA();
|
||||
if (!env) return;
|
||||
#if defined(_WIN32)
|
||||
// Windows: use WinAPI
|
||||
LPCH env = GetEnvironmentStringsA();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
for (LPCH var = env; *var; var += strlen(var) + 1) {
|
||||
// Each string is like "KEY=VALUE"
|
||||
const char *equals = strchr(var, '=');
|
||||
if (equals) {
|
||||
size_t key_len = equals - var;
|
||||
char key[256];
|
||||
if (key_len >= sizeof(key))
|
||||
key_len = sizeof(key) - 1;
|
||||
strncpy(key, var, key_len);
|
||||
key[key_len] = '\0';
|
||||
for (LPCH var = env; *var; var += strlen(var) + 1) {
|
||||
// Each string is like "KEY=VALUE"
|
||||
const char *equals = strchr(var, '=');
|
||||
if (equals) {
|
||||
size_t key_len = equals - var;
|
||||
char key[256];
|
||||
if (key_len >= sizeof(key))
|
||||
key_len = sizeof(key) - 1;
|
||||
strncpy(key, var, key_len);
|
||||
key[key_len] = '\0';
|
||||
|
||||
const char *value = getenv(key);
|
||||
add_to_hashmap(environment_variables, key,
|
||||
value?new_string_object_null_terminated((char *)value):ARGON_NULL);
|
||||
}
|
||||
const char *value = getenv(key);
|
||||
add_to_hashmap(environment_variables, key,
|
||||
value ? new_string_object_null_terminated((char *)value)
|
||||
: ARGON_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
FreeEnvironmentStringsA(env);
|
||||
FreeEnvironmentStringsA(env);
|
||||
#else
|
||||
// POSIX systems: use environ
|
||||
for (char **env = environ; *env != NULL; env++) {
|
||||
const char *equals = strchr(*env, '=');
|
||||
if (equals) {
|
||||
size_t key_len = equals - *env;
|
||||
char key[256];
|
||||
if (key_len >= sizeof(key))
|
||||
key_len = sizeof(key) - 1;
|
||||
strncpy(key, *env, key_len);
|
||||
key[key_len] = '\0';
|
||||
// POSIX systems: use environ
|
||||
for (char **env = environ; *env != NULL; env++) {
|
||||
const char *equals = strchr(*env, '=');
|
||||
if (equals) {
|
||||
size_t key_len = equals - *env;
|
||||
char key[256];
|
||||
if (key_len >= sizeof(key))
|
||||
key_len = sizeof(key) - 1;
|
||||
strncpy(key, *env, key_len);
|
||||
key[key_len] = '\0';
|
||||
|
||||
const char *value = getenv(key);
|
||||
add_to_hashmap(environment_variables, key,
|
||||
value?new_string_object_null_terminated((char *)value):ARGON_NULL);
|
||||
}
|
||||
const char *value = getenv(key);
|
||||
add_to_hashmap(environment_variables, key,
|
||||
value ? new_string_object_null_terminated((char *)value)
|
||||
: ARGON_NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
add_to_scope(Global_Scope, "env", create_dictionary(environment_variables));
|
||||
@@ -885,7 +892,10 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack,
|
||||
[OP_MULTIPLICATION] = &&DO_MULTIPLICATION,
|
||||
[OP_DIVISION] = &&DO_DIVISION,
|
||||
[OP_NOT] = &&DO_NOT,
|
||||
[OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD};
|
||||
[OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD,
|
||||
[OP_CREATE_DICTIONARY] = &&DO_CREATE_DICTIONARY,
|
||||
[OP_LOAD_SETITEM_METHOD] = &&DO_LOAD_SETITEM_METHOD,
|
||||
[OP_LOAD_GETITEM_METHOD] = &&DO_LOAD_GETITEM_METHOD};
|
||||
_state.head = 0;
|
||||
|
||||
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
|
||||
@@ -1257,13 +1267,41 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack,
|
||||
}
|
||||
DO_LOAD_SETATTR_METHOD: {
|
||||
state->registers[0] = get_builtin_field_for_class(
|
||||
get_builtin_field(state->registers[0], __class__), __set_attr__,
|
||||
get_builtin_field(state->registers[0], __class__), __setattr__,
|
||||
state->registers[0]);
|
||||
if (!state->registers[0]) {
|
||||
*err = create_err(
|
||||
state->source_location.line, state->source_location.column,
|
||||
state->source_location.length, state->path, "Runtime Error",
|
||||
"unable to get __set_attr__ from objects class");
|
||||
"unable to get __setattr__ from objects class");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
DO_CREATE_DICTIONARY: {
|
||||
state->registers[0] = create_dictionary(createHashmap_GC());
|
||||
continue;
|
||||
}
|
||||
DO_LOAD_SETITEM_METHOD: {
|
||||
state->registers[0] = get_builtin_field_for_class(
|
||||
get_builtin_field(state->registers[0], __class__), __setitem__,
|
||||
state->registers[0]);
|
||||
if (!state->registers[0]) {
|
||||
*err = create_err(
|
||||
state->source_location.line, state->source_location.column,
|
||||
state->source_location.length, state->path, "Runtime Error",
|
||||
"unable to get __setitem__ from objects class");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
DO_LOAD_GETITEM_METHOD: {
|
||||
state->registers[0] = get_builtin_field_for_class(
|
||||
get_builtin_field(state->registers[0], __class__), __getitem__,
|
||||
state->registers[0]);
|
||||
if (!state->registers[0]) {
|
||||
*err = create_err(
|
||||
state->source_location.line, state->source_location.column,
|
||||
state->source_location.length, state->path, "Runtime Error",
|
||||
"unable to get __getitem__ from objects class");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#define MAX_REGISTERS 256
|
||||
|
||||
extern ArgonObject *ARGON_METHOD_TYPE;
|
||||
extern Stack *Global_Scope;
|
||||
|
||||
|
||||
62
src/shell.c
62
src/shell.c
@@ -43,37 +43,44 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Only define ssize_t if it doesn't already exist
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
typedef long ssize_t;
|
||||
#define _SSIZE_T_DEFINED
|
||||
#endif
|
||||
|
||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
if (!lineptr || !n || !stream) return -1;
|
||||
if (!lineptr || !n || !stream)
|
||||
return -1;
|
||||
|
||||
size_t pos = 0;
|
||||
int c;
|
||||
size_t pos = 0;
|
||||
int c;
|
||||
|
||||
if (*lineptr == NULL || *n == 0) {
|
||||
*n = 128;
|
||||
*lineptr = malloc(*n);
|
||||
if (!*lineptr) return -1;
|
||||
}
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
(*lineptr)[pos] = '\0';
|
||||
return (ssize_t)pos;
|
||||
if (pos == 0 && c == EOF)
|
||||
return -1;
|
||||
|
||||
(*lineptr)[pos] = '\0';
|
||||
return (ssize_t)pos;
|
||||
}
|
||||
#else
|
||||
#include "../external/linenoise/linenoise.h"
|
||||
@@ -205,7 +212,6 @@ char *read_all_stdin(size_t *out_len) {
|
||||
}
|
||||
|
||||
int shell() {
|
||||
|
||||
Stack *main_scope = create_scope(Global_Scope, true);
|
||||
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
@@ -224,8 +230,9 @@ int shell() {
|
||||
|
||||
signal(SIGINT, handle_sigint);
|
||||
|
||||
printf("Argon (Chloride %s)\nType \"license\" for more information.\n",
|
||||
version_string);
|
||||
printf("Chloride %s Copyright (C) 2025 William Bell\n"
|
||||
"This program comes with ABSOLUTELY NO WARRANTY; for details type `license'.\n"
|
||||
"This is free software, and you are welcome to redistribute it under certain conditions; type `license' for details.\n", version_string);
|
||||
|
||||
ArgonObject *output_object = create_argon_native_function("log", term_log);
|
||||
char *totranslate = NULL;
|
||||
@@ -308,7 +315,8 @@ int shell() {
|
||||
if (resp) {
|
||||
continue;
|
||||
}
|
||||
if (runtime_state.registers[0]&&runtime_state.registers[0] != ARGON_NULL) {
|
||||
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,
|
||||
|
||||
@@ -122,11 +122,11 @@ sets the source location onto the runtime
|
||||
|
||||
## OP_LOAD_GETATTRIBUTE_METHOD
|
||||
|
||||
loads the \_\_getattribute\_\_ method from the objects class in register 1 and put it into register 1
|
||||
loads the \_\_getattribute\_\_ method from the objects class in register 0 and put it into register 0
|
||||
|
||||
## OP_LOAD_BOOL
|
||||
|
||||
loads a boolean into register 1
|
||||
loads a boolean into register 0
|
||||
|
||||
1. byte representing true or false (1 or 0) *
|
||||
|
||||
@@ -187,4 +187,16 @@ 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
|
||||
loads the \_\_setattr\_\_ method from the objects class in register 0 and put it into register 0
|
||||
|
||||
## OP_CREATE_DICTIONARY
|
||||
|
||||
create a dictionary object into register 0.
|
||||
|
||||
## OP_LOAD_GETITEM_METHOD
|
||||
|
||||
loads the \_\_getitem\_\_ method from the objects class in register 0 and put it into register 0
|
||||
|
||||
## OP_LOAD_SETITEM_METHOD
|
||||
|
||||
loads the \_\_setitem\_\_ method from the objects class in register 0 and put it into register 0
|
||||
33
src/translator/item_access/item_access.c
Normal file
33
src/translator/item_access/item_access.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
#include "item_access.h"
|
||||
#include <stddef.h>
|
||||
|
||||
size_t translate_item_access(Translated *translated, ParsedItemAccess *access,
|
||||
ArErr *err) {
|
||||
set_registers(translated, 1);
|
||||
uint64_t first = translate_parsed(translated, access->to_access, err);
|
||||
if (err->exists)
|
||||
return 0;
|
||||
push_instruction_byte(translated, OP_LOAD_GETITEM_METHOD);
|
||||
push_instruction_byte(translated, OP_INIT_CALL);
|
||||
push_instruction_code(translated, access->itemc);
|
||||
|
||||
for (size_t i = 0; i < access->itemc; i++) {
|
||||
translate_parsed(translated, access->items[i], err);
|
||||
if (err->exists)
|
||||
return 0;
|
||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||
push_instruction_code(translated, i);
|
||||
}
|
||||
|
||||
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
||||
push_instruction_code(translated, access->line);
|
||||
push_instruction_code(translated, access->column);
|
||||
push_instruction_code(translated, access->length);
|
||||
push_instruction_byte(translated, OP_CALL);
|
||||
return first;
|
||||
}
|
||||
15
src/translator/item_access/item_access.h
Normal file
15
src/translator/item_access/item_access.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef translator_item_access_H
|
||||
#define translator_item_access_H
|
||||
#include "../../parser/assignable/item/item.h"
|
||||
#include "../translator.h"
|
||||
|
||||
size_t translate_item_access(Translated *translated, ParsedItemAccess *access,
|
||||
ArErr *err);
|
||||
|
||||
#endif // translator_item_access_H
|
||||
@@ -6,8 +6,11 @@
|
||||
|
||||
#include "translator.h"
|
||||
#include "../hash_data/hash_data.h"
|
||||
#include "../parser/dictionary/dictionary.h"
|
||||
#include "../parser/not/not.h"
|
||||
#include "access/access.h"
|
||||
#include "../parser/assignable/item/item.h"
|
||||
#include "item_access/item_access.h"
|
||||
#include "assignment/assignment.h"
|
||||
#include "call/call.h"
|
||||
#include "declaration/declaration.h"
|
||||
@@ -162,6 +165,8 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
|
||||
err);
|
||||
case AST_ACCESS:
|
||||
return translate_access(translated, (ParsedAccess *)parsedValue->data, err);
|
||||
case AST_ITEM_ACCESS:
|
||||
return translate_item_access(translated, (ParsedItemAccess *)parsedValue->data, err);
|
||||
case AST_OPERATION:
|
||||
return translate_operation(translated, (ParsedOperation *)parsedValue->data,
|
||||
err);
|
||||
@@ -176,6 +181,67 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
|
||||
push_instruction_byte(translated, OP_NOT);
|
||||
return first;
|
||||
}
|
||||
case AST_DICTIONARY: {
|
||||
DArray *dictionaryDarray = parsedValue->data;
|
||||
|
||||
size_t first = push_instruction_byte(translated, OP_CREATE_DICTIONARY);
|
||||
uint8_t dictionaryRegister = translated->registerAssignment++;
|
||||
|
||||
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||
push_instruction_byte(translated, 0);
|
||||
push_instruction_byte(translated, dictionaryRegister);
|
||||
|
||||
push_instruction_byte(translated, OP_LOAD_SETITEM_METHOD);
|
||||
uint8_t setitemRegister = translated->registerAssignment++;
|
||||
set_registers(translated, translated->registerAssignment);
|
||||
|
||||
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||
push_instruction_byte(translated, 0);
|
||||
push_instruction_byte(translated, setitemRegister);
|
||||
|
||||
for (size_t i = 0; i < dictionaryDarray->size; i++) {
|
||||
ParsedDictionaryEntry *entry = darray_get(dictionaryDarray, i);
|
||||
if (i != 0) {
|
||||
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||
push_instruction_byte(translated, setitemRegister);
|
||||
push_instruction_byte(translated, 0);
|
||||
}
|
||||
push_instruction_byte(translated, OP_INIT_CALL);
|
||||
push_instruction_code(translated, 2);
|
||||
|
||||
translate_parsed(translated, entry->key, err);
|
||||
if (err->exists)
|
||||
return first;
|
||||
|
||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||
push_instruction_code(translated, 0);
|
||||
|
||||
translate_parsed(translated, entry->value, err);
|
||||
if (err->exists)
|
||||
return first;
|
||||
|
||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||
push_instruction_code(translated, 1);
|
||||
|
||||
push_instruction_byte(translated, OP_CALL);
|
||||
}
|
||||
|
||||
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||
push_instruction_byte(translated, dictionaryRegister);
|
||||
push_instruction_byte(translated, 0);
|
||||
|
||||
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||
push_instruction_byte(translated, dictionaryRegister);
|
||||
|
||||
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||
push_instruction_byte(translated, setitemRegister);
|
||||
|
||||
translated->registerAssignment-=2;
|
||||
return first;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "panic: undefined translation\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,10 @@ typedef enum {
|
||||
OP_MULTIPLICATION,
|
||||
OP_DIVISION,
|
||||
OP_NOT,
|
||||
OP_LOAD_SETATTR_METHOD
|
||||
OP_LOAD_SETATTR_METHOD,
|
||||
OP_CREATE_DICTIONARY,
|
||||
OP_LOAD_GETITEM_METHOD,
|
||||
OP_LOAD_SETITEM_METHOD
|
||||
} OperationType;
|
||||
|
||||
void arena_resize(ConstantArena *arena, size_t new_size);
|
||||
|
||||
@@ -1 +1,9 @@
|
||||
term.log("hello world")
|
||||
term.log(()=10)
|
||||
term.log((x)=10)
|
||||
term.log((x,y)=10)
|
||||
term.log((x,y,z)=10)
|
||||
term.log(a()=10)
|
||||
term.log(b(x)=10)
|
||||
term.log(c(x,y)=10)
|
||||
term.log(d(x,y,z)=10)
|
||||
5
tests/class_method.ar
Normal file
5
tests/class_method.ar
Normal file
@@ -0,0 +1,5 @@
|
||||
string.cool(self) = do
|
||||
term.log(self, self.length)
|
||||
return 10
|
||||
'hello world'.cool()
|
||||
string.cool('goodbye world')
|
||||
16
tests/diff.ar
Normal file
16
tests/diff.ar
Normal file
@@ -0,0 +1,16 @@
|
||||
let h = 1e-1000
|
||||
let diff(f) = (x) = (f(x + h) - f(x)) / h
|
||||
|
||||
|
||||
let f(x) = x*x*x*x*x*x*x*x*x*x+2*x*x*x*x*x*x*x*x*x+3*x*x*x*x*x*x*x*x+4*x*x*x*x*x*x*x+5*x*x*x*x*x*x+6*x*x*x*x*x+7*x*x*x*x+8*x*x*x+9*x*x+10*x+11
|
||||
let x = 100
|
||||
let d = 0
|
||||
|
||||
do
|
||||
while (true) do
|
||||
let n = f(x)
|
||||
term.log("f"+string(d)+"("+string(x)+") = "+string(n))
|
||||
if (n) do
|
||||
f = diff(f)
|
||||
d = d + 1
|
||||
else return
|
||||
10
tests/factorial.ar
Normal file
10
tests/factorial.ar
Normal file
@@ -0,0 +1,10 @@
|
||||
let factorial(x) = do
|
||||
let n = x-1
|
||||
if (n) return x*factorial(n)
|
||||
return 1
|
||||
|
||||
let loop = 501
|
||||
let x = 500
|
||||
while (x) do
|
||||
factorial(loop-x)
|
||||
x=x-1
|
||||
2
tests/hashmap_creation_seg_fault.ar
Normal file
2
tests/hashmap_creation_seg_fault.ar
Normal file
@@ -0,0 +1,2 @@
|
||||
while (true) do
|
||||
{"z": 1, "b": 2, "c": 3, "a": 7}
|
||||
23
tests/hashmap_order.ar
Normal file
23
tests/hashmap_order.ar
Normal file
@@ -0,0 +1,23 @@
|
||||
let x = {'p':1}
|
||||
x.z = 1
|
||||
x.b = 2
|
||||
x.c = 3
|
||||
x.a = 7
|
||||
term.log(x)
|
||||
|
||||
let y = {}
|
||||
y.a = 1
|
||||
y.b = 2
|
||||
y.c = 3
|
||||
y.d = 7
|
||||
y.e = 2
|
||||
y.f = 3
|
||||
y.g = 7
|
||||
y.h = 1
|
||||
y.i = 2
|
||||
y.j = 3
|
||||
y.k = 7
|
||||
y.l = 2
|
||||
y.m = 3
|
||||
y.n = 7
|
||||
term.log(y)
|
||||
2
tests/hashmap_to_array_seg_fault.ar
Normal file
2
tests/hashmap_to_array_seg_fault.ar
Normal file
@@ -0,0 +1,2 @@
|
||||
while (true) do
|
||||
term.log(global)
|
||||
@@ -1,4 +0,0 @@
|
||||
term.log(global)
|
||||
let i = 1e8
|
||||
while (i) do
|
||||
i=i-1
|
||||
@@ -1,3 +0,0 @@
|
||||
i = 1000000
|
||||
while i:
|
||||
i=i-1
|
||||
3
tests/iteration.ar
Normal file
3
tests/iteration.ar
Normal file
@@ -0,0 +1,3 @@
|
||||
let i = 1e7
|
||||
while (i) do
|
||||
i=i-1
|
||||
1
tests/null_plus_one.ar
Normal file
1
tests/null_plus_one.ar
Normal file
@@ -0,0 +1 @@
|
||||
null+1
|
||||
@@ -1,6 +1,6 @@
|
||||
let i = 10
|
||||
let x = 1
|
||||
let n = 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000 * 1e1000000
|
||||
while (i) do
|
||||
x = x * 1e100000000
|
||||
x = x*n
|
||||
term.log(i=i-1)
|
||||
term.log(x)
|
||||
Reference in New Issue
Block a user