Compare commits
65 Commits
release-v4
...
357c8745a4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
6d3e79b731 | ||
|
|
b3ee64d294 | ||
|
|
e6ec0fa38a | ||
|
|
c8394228b3 | ||
| 70ba81bebc | |||
|
|
50ff9fbefc | ||
|
|
042c278b8d | ||
|
|
81efaaac07 | ||
| 3b0ec79955 | |||
|
|
4be8e8e32f | ||
|
|
5846adf025 | ||
|
|
daa8056b7a | ||
|
|
1a5abd9543 | ||
|
|
774890de1d | ||
|
|
fc7cfc7cfb | ||
|
|
d46a6dc209 | ||
|
|
23c4a7ebd1 | ||
|
|
57728af0b6 | ||
|
|
df040adf45 | ||
|
|
c2e0cdc6d6 | ||
|
|
571efe46b7 | ||
|
|
67569bffc2 | ||
|
|
f5ee0f6fc8 | ||
|
|
fd5b237dfe | ||
|
|
322716af0c | ||
|
|
c67b37d8b2 | ||
|
|
b9c0503d54 | ||
|
|
19268f3070 | ||
|
|
4f91bf48f3 | ||
|
|
4fc28d3b76 | ||
| c01dee80b0 | |||
| 0f0a3f5d31 | |||
|
|
f598c215e7 | ||
|
|
fff4f6bcb5 | ||
|
|
c322d5680f | ||
|
|
db650d8ccf | ||
|
|
6ad0b2c02e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -64,5 +64,6 @@ build
|
|||||||
*.yy.c
|
*.yy.c
|
||||||
*.yy.h
|
*.yy.h
|
||||||
|
|
||||||
|
__isotope__
|
||||||
__arcache__
|
__arcache__
|
||||||
argon_modules
|
argon_modules
|
||||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -9,7 +9,7 @@
|
|||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/argon",
|
"program": "${workspaceFolder}/bin/argon",
|
||||||
"args": ["testing.ar"],
|
"args": [],
|
||||||
"stopAtEntry": true,
|
"stopAtEntry": true,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
|
|||||||
68
Jenkinsfile
vendored
Normal file
68
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
sh 'git submodule update --init --recursive'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Setup Conan') {
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
python3 -m venv /tmp/venv
|
||||||
|
. /tmp/venv/bin/activate
|
||||||
|
apt update
|
||||||
|
apt upgrade
|
||||||
|
apt install -y cmake flex python3 python3-pip python3-venv
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install conan
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Setup Conan Profile') {
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
. /tmp/venv/bin/activate
|
||||||
|
if [ ! -f ~/.conan2/profiles/default ]; then
|
||||||
|
conan profile detect
|
||||||
|
fi
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Install Dependencies') {
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
. /tmp/venv/bin/activate
|
||||||
|
conan install . --build=missing
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build Project') {
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
. /tmp/venv/bin/activate
|
||||||
|
conan build .
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Archive Build Artifacts') {
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
# Copy LICENSE.txt into build/bin
|
||||||
|
cp LICENSE.txt build/bin/
|
||||||
|
|
||||||
|
# Create tarball with the contents of build/bin at the root
|
||||||
|
tar -czf chloride.tar.gz -C build/bin .
|
||||||
|
'''
|
||||||
|
// Archive the tarball
|
||||||
|
archiveArtifacts artifacts: 'chloride.tar.gz', allowEmptyArchive: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Makefile
2
Makefile
@@ -34,7 +34,7 @@ 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) ${LDFLAGS}
|
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
|
||||||
|
|||||||
77
README.md
77
README.md
@@ -4,6 +4,79 @@ SPDX-FileCopyrightText: 2025 William Bell
|
|||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
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
|
# Remove tool_requires, no flex from Conan
|
||||||
requires = [
|
requires = [
|
||||||
"gmp/6.3.0",
|
"gmp/6.3.0",
|
||||||
"bdwgc/8.2.8"
|
"bdwgc/8.2.6"
|
||||||
]
|
]
|
||||||
|
|
||||||
default_options = {
|
default_options = {
|
||||||
"gmp/*:shared": False,
|
"gmp/*:shared": False,
|
||||||
"bdwgc/*:shared": False
|
"bdwgc/*:shared": False,
|
||||||
|
"bdwgc/*:parallel_mark": False,
|
||||||
|
"bdwgc/*:threads": True,
|
||||||
|
"bdwgc/*:disable_debug": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
|
|||||||
130
debug_arbin.py
130
debug_arbin.py
@@ -1,130 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import struct
|
|
||||||
from enum import Enum, EnumMeta, auto
|
|
||||||
|
|
||||||
class AutoEnumMeta(EnumMeta):
|
|
||||||
@classmethod
|
|
||||||
def __prepare__(metacls, clsname, bases, **kwargs):
|
|
||||||
d = super().__prepare__(clsname, bases, **kwargs)
|
|
||||||
d['_next_value'] = 254
|
|
||||||
return d
|
|
||||||
|
|
||||||
def _generate_next_value_(cls, name, start, count, last_values):
|
|
||||||
value = cls._next_value
|
|
||||||
cls._next_value += 1
|
|
||||||
return value
|
|
||||||
|
|
||||||
class OperationType(Enum, metaclass=AutoEnumMeta):
|
|
||||||
OP_LOAD_CONST = auto()
|
|
||||||
OP_DECLARE = auto()
|
|
||||||
OP_LOAD_NULL = auto()
|
|
||||||
OP_JUMP = auto()
|
|
||||||
|
|
||||||
class Types(Enum, metaclass=AutoEnumMeta):
|
|
||||||
TYPE_OP_STRING = auto()
|
|
||||||
TYPE_OP_NUMBER = auto()
|
|
||||||
|
|
||||||
def read_arbin(filename):
|
|
||||||
with open(filename, "rb") as f:
|
|
||||||
# Read and verify file identifier (4 bytes)
|
|
||||||
file_id = f.read(4)
|
|
||||||
if file_id != b"ARBI":
|
|
||||||
raise ValueError("Invalid file identifier")
|
|
||||||
|
|
||||||
# Read version number (uint64_t, little-endian)
|
|
||||||
version_number, = struct.unpack("<Q", f.read(8))
|
|
||||||
|
|
||||||
# Read regCount, constantsSize, bytecodeSize (all uint64_t, little-endian)
|
|
||||||
reg_count, = struct.unpack("<Q", f.read(8))
|
|
||||||
constants_size, = struct.unpack("<Q", f.read(8))
|
|
||||||
bytecode_size, = struct.unpack("<Q", f.read(8))
|
|
||||||
|
|
||||||
# Read constants buffer (raw bytes)
|
|
||||||
constants = f.read(constants_size)
|
|
||||||
|
|
||||||
# Read bytecode array (uint64_t, little-endian)
|
|
||||||
bytecode = []
|
|
||||||
for _ in range(bytecode_size):
|
|
||||||
instr, = struct.unpack("<Q", f.read(8))
|
|
||||||
bytecode.append(instr)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"version": version_number,
|
|
||||||
"register_count": reg_count,
|
|
||||||
"constants_size": constants_size,
|
|
||||||
"bytecode_size": bytecode_size,
|
|
||||||
"constants": constants,
|
|
||||||
"bytecode": bytecode,
|
|
||||||
}
|
|
||||||
|
|
||||||
class print_opcode:
|
|
||||||
def start(registers,data, i):
|
|
||||||
print()
|
|
||||||
match data['bytecode'][i]:
|
|
||||||
case OperationType.OP_LOAD_CONST.value:
|
|
||||||
return print_opcode.OP_LOAD_CONST(registers,data, i)
|
|
||||||
case OperationType.OP_DECLARE.value:
|
|
||||||
return print_opcode.OP_DECLARE(registers,data, i)
|
|
||||||
case OperationType.OP_LOAD_NULL.value:
|
|
||||||
return print_opcode.OP_LOAD_NULL(registers,data, i)
|
|
||||||
|
|
||||||
def OP_LOAD_CONST(registers,data, i) -> int:
|
|
||||||
print("OP_LOAD_CONST ", end="")
|
|
||||||
i+=1
|
|
||||||
register = data["bytecode"][i]
|
|
||||||
print("To Register",register,"", end="")
|
|
||||||
i+=1
|
|
||||||
match data["bytecode"][i]:
|
|
||||||
case Types.TYPE_OP_STRING.value:
|
|
||||||
print("TYPE_OP_STRING ", end="")
|
|
||||||
case Types.TYPE_OP_NUMBER.value:
|
|
||||||
print("TYPE_OP_NUMBER ", end="")
|
|
||||||
i+=1
|
|
||||||
length = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
offset = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
print("Length",length,"", end="")
|
|
||||||
print("Offset",offset,"")
|
|
||||||
registers[register] = data["constants"][offset:offset+length].decode()
|
|
||||||
print("const value:", registers[register])
|
|
||||||
return i
|
|
||||||
|
|
||||||
def OP_DECLARE(registers,data, i) -> int:
|
|
||||||
print("OP_DECLARE ", end="")
|
|
||||||
i+=1
|
|
||||||
length = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
offset = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
from_register = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
print("Name Length",length,"", end="")
|
|
||||||
print("Name Offset",offset,"", end="")
|
|
||||||
print("From Register",from_register,"")
|
|
||||||
print("output: let", data['constants'][offset:offset+length].decode(),'=',registers[from_register])
|
|
||||||
return i
|
|
||||||
def OP_LOAD_NULL(registers,data, i) -> int:
|
|
||||||
print("OP_LOAD_NULL ", end="")
|
|
||||||
i+=1
|
|
||||||
to_register = data["bytecode"][i]
|
|
||||||
i+=1
|
|
||||||
print("To Register",to_register,"")
|
|
||||||
registers[to_register] = "null"
|
|
||||||
return i
|
|
||||||
if __name__ == "__main__":
|
|
||||||
filename = "out.arbin"
|
|
||||||
data = read_arbin(filename)
|
|
||||||
print(f"Version: {data['version']}")
|
|
||||||
print(f"Register Count: {data['register_count']}")
|
|
||||||
print(f"Constants Size: {data['constants_size']} bytes")
|
|
||||||
print(f"Bytecode Length: {data['bytecode_size']} elements")
|
|
||||||
|
|
||||||
registers = ["null"]*data['register_count']
|
|
||||||
|
|
||||||
i=0
|
|
||||||
while i<len(data["bytecode"]):
|
|
||||||
i=print_opcode.start(registers,data,i)
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
let __makeFile(name, type, data) = do
|
|
||||||
let File = {name: name, type: type, data: data}
|
|
||||||
let save(path) = do
|
|
||||||
let file = file.write(path)
|
|
||||||
file.buffer(data)
|
|
||||||
file.close()
|
|
||||||
File.save = save
|
|
||||||
return File
|
|
||||||
|
|
||||||
let __multipart(req, res) = do
|
|
||||||
let boundary = buffer().from(req.headers["content-type"].splitN("boundary=", 2)[1])
|
|
||||||
let newLineSplit = buffer().from("\r\n\r\n")
|
|
||||||
let parts = req.buffer.body.split(boundary)
|
|
||||||
for (i from 0 to parts.length) do
|
|
||||||
let str = parts[i].to("string")
|
|
||||||
if (str == "" || str=="--" || str=="--\r\n") continue
|
|
||||||
str = null
|
|
||||||
let headers = {}
|
|
||||||
let lines = parts[i].splitN(newLineSplit, 2)
|
|
||||||
let headerLines = lines[0].to("string").split("\r\n")
|
|
||||||
for (j from 0 to headerLines.length) do
|
|
||||||
let header = headerLines[j].splitN(": ", 2)
|
|
||||||
if (header.length != 2) continue
|
|
||||||
headers[header[0].lower()] = header[1]
|
|
||||||
if (lines.length != 2) continue
|
|
||||||
let body = lines[1]
|
|
||||||
if (i != parts.length-1) do
|
|
||||||
body = body.slice(0, body.length-4)
|
|
||||||
if ("content-disposition" in headers) do
|
|
||||||
let disposition = headers["content-disposition"].split("; ")
|
|
||||||
if (disposition[0] == "form-data") do
|
|
||||||
let name = json.parse(disposition[1].splitN("=", 2)[1])
|
|
||||||
if (disposition.length >= 3) do
|
|
||||||
let filename = json.parse(disposition[2].splitN("=", 2)[1])
|
|
||||||
req.files[name] = __makeFile(filename, headers["content-type"], body)
|
|
||||||
else do
|
|
||||||
req.formdata[name] = body.to("string")
|
|
||||||
res.next()
|
|
||||||
|
|
||||||
|
|
||||||
let formdata(req, res) = do
|
|
||||||
req.formdata = {}
|
|
||||||
req.files = {}
|
|
||||||
|
|
||||||
if (req.method != "POST") return res.next()
|
|
||||||
if ("content-type" not in req.headers) return res.next()
|
|
||||||
let loweredContentType = req.headers["content-type"].lower()
|
|
||||||
if (loweredContentType.startswith("multipart/form-data")) return __multipart(req, res)
|
|
||||||
else if (loweredContentType.startswith("application/x-www-form-urlencoded")) req.formdata = url.decodeURLQuery(req.buffer.body.to("string"))
|
|
||||||
else if (loweredContentType.startswith("application/json")) req.formdata = json.parse(req.buffer.body.to("string"))
|
|
||||||
else req.files.file = __makeFile("file", req.headers["content-type"], req.buffer.body)
|
|
||||||
res.next()
|
|
||||||
10
gentest.py
10
gentest.py
@@ -1,10 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import random
|
|
||||||
import sys
|
|
||||||
|
|
||||||
for i in range(10000000):
|
|
||||||
sys.stdout.write("\"hello world\"\n")
|
|
||||||
|
|
||||||
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 |
2893
src/LICENSE_c.h
Normal file
2893
src/LICENSE_c.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,38 @@
|
|||||||
#include "runtime/internals/hashmap/hashmap.h"
|
#include "runtime/internals/hashmap/hashmap.h"
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
__base__,
|
||||||
|
__class__,
|
||||||
|
__name__,
|
||||||
|
|
||||||
|
BUILT_IN_ARRAY_COUNT,
|
||||||
|
|
||||||
|
__binding__,
|
||||||
|
__function__,
|
||||||
|
__add__,
|
||||||
|
__string__,
|
||||||
|
__subtract__,
|
||||||
|
__multiply__,
|
||||||
|
__divide__,
|
||||||
|
__new__,
|
||||||
|
__init__,
|
||||||
|
__boolean__,
|
||||||
|
__getattr__,
|
||||||
|
field__address,
|
||||||
|
__call__,
|
||||||
|
__number__,
|
||||||
|
field_length,
|
||||||
|
__getattribute__,
|
||||||
|
__setattr__,
|
||||||
|
__getitem__,
|
||||||
|
__setitem__,
|
||||||
|
__hash__,
|
||||||
|
__repr__,
|
||||||
|
|
||||||
|
BUILT_IN_FIELDS_COUNT,
|
||||||
|
} built_in_fields;
|
||||||
|
|
||||||
typedef struct ArErr ArErr;
|
typedef struct ArErr ArErr;
|
||||||
typedef struct RuntimeState RuntimeState;
|
typedef struct RuntimeState RuntimeState;
|
||||||
|
|
||||||
@@ -28,6 +60,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 +73,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 +81,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 +105,33 @@ struct argon_function_struct {
|
|||||||
uint64_t column;
|
uint64_t column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct built_in_slot {
|
||||||
|
built_in_fields field;
|
||||||
|
ArgonObject *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct as_number {
|
||||||
|
union {
|
||||||
|
mpq_t *mpq;
|
||||||
|
int64_t i64;
|
||||||
|
} n;
|
||||||
|
bool is_int64;
|
||||||
|
};
|
||||||
|
|
||||||
// full definition of ArgonObject (no typedef again!)
|
// full definition of ArgonObject (no typedef again!)
|
||||||
struct ArgonObject {
|
struct ArgonObject {
|
||||||
ArgonType type;
|
|
||||||
ArgonType child_type;
|
|
||||||
struct hashmap_GC *dict;
|
struct hashmap_GC *dict;
|
||||||
|
size_t built_in_slot_length;
|
||||||
|
struct built_in_slot built_in_slot[BUILT_IN_ARRAY_COUNT];
|
||||||
union {
|
union {
|
||||||
mpq_t *as_number;
|
struct as_number *as_number;
|
||||||
struct string_struct as_str;
|
struct hashmap_GC *as_hashmap;
|
||||||
|
struct string_struct *as_str;
|
||||||
native_fn native_fn;
|
native_fn native_fn;
|
||||||
struct argon_function_struct argon_fn;
|
struct argon_function_struct *argon_fn;
|
||||||
} value;
|
} value;
|
||||||
|
ArgonType type;
|
||||||
|
bool as_bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AROBJECT_H
|
#endif // AROBJECT_H
|
||||||
21
src/err.c
21
src/err.c
@@ -7,6 +7,7 @@
|
|||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "../external/libdye/include/dye.h"
|
#include "../external/libdye/include/dye.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
@@ -61,20 +61,23 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const ArErr no_err = (ArErr){false};
|
const ArErr no_err = (ArErr){"", "", "", 0, 0, 0, false};
|
||||||
|
|
||||||
ArErr create_err(int64_t line, int64_t column, int length, char *path,
|
ArErr create_err(int64_t line, int64_t column, int length, char *path,
|
||||||
const char *type, const char *fmt, ...) {
|
const char *type, const char *fmt, ...) {
|
||||||
ArErr err;
|
ArErr err;
|
||||||
err.exists = true;
|
err.exists = true;
|
||||||
err.path = path;
|
if (path)
|
||||||
|
strcpy(err.path, path);
|
||||||
|
else {
|
||||||
|
err.path[0] = '\0';
|
||||||
|
}
|
||||||
err.line = line;
|
err.line = line;
|
||||||
err.column = column;
|
err.column = column;
|
||||||
err.length = length;
|
err.length = length;
|
||||||
|
|
||||||
// Copy error type safely
|
// Copy error type safely
|
||||||
strncpy(err.type, type, sizeof(err.type) - 1);
|
snprintf(err.type, sizeof(err.type), "%s", (char *)type);
|
||||||
err.type[sizeof(err.type) - 1] = '\0';
|
|
||||||
|
|
||||||
// Format error message
|
// Format error message
|
||||||
va_list args;
|
va_list args;
|
||||||
@@ -104,7 +107,7 @@ void output_err(ArErr err) {
|
|||||||
dyefg(stderr, DYE_RESET);
|
dyefg(stderr, DYE_RESET);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
if (err.path && err.line) {
|
if (strlen(err.path) && err.line) {
|
||||||
dyefg(stderr, DYE_GRAY);
|
dyefg(stderr, DYE_GRAY);
|
||||||
fprintf(stderr, " --> ");
|
fprintf(stderr, " --> ");
|
||||||
dyefg(stderr, DYE_CYAN);
|
dyefg(stderr, DYE_CYAN);
|
||||||
@@ -112,7 +115,7 @@ void output_err(ArErr err) {
|
|||||||
dyefg(stderr, DYE_GRAY);
|
dyefg(stderr, DYE_GRAY);
|
||||||
fprintf(stderr, ":");
|
fprintf(stderr, ":");
|
||||||
dyefg(stderr, DYE_YELLOW);
|
dyefg(stderr, DYE_YELLOW);
|
||||||
fprintf(stderr, "%" PRIu64 , err.line);
|
fprintf(stderr, "%" PRIu64, err.line);
|
||||||
dyefg(stderr, DYE_GRAY);
|
dyefg(stderr, DYE_GRAY);
|
||||||
fprintf(stderr, ":");
|
fprintf(stderr, ":");
|
||||||
dyefg(stderr, DYE_YELLOW);
|
dyefg(stderr, DYE_YELLOW);
|
||||||
@@ -141,7 +144,7 @@ void output_err(ArErr err) {
|
|||||||
fprintf(stderr, " ");
|
fprintf(stderr, " ");
|
||||||
}
|
}
|
||||||
fprintf(stderr, "|\n");
|
fprintf(stderr, "|\n");
|
||||||
for (ssize_t i = 0;i<len;i++) {
|
for (ssize_t i = 0; i < len; i++) {
|
||||||
if (buffer[i] == '\n') {
|
if (buffer[i] == '\n') {
|
||||||
buffer[i] = '\0';
|
buffer[i] = '\0';
|
||||||
break;
|
break;
|
||||||
@@ -165,7 +168,7 @@ void output_err(ArErr err) {
|
|||||||
dyefg(stderr, DYE_RESET);
|
dyefg(stderr, DYE_RESET);
|
||||||
fprintf(stderr, "%.*s",
|
fprintf(stderr, "%.*s",
|
||||||
(int)len - (int)skipped_chars - (int)err.column -
|
(int)len - (int)skipped_chars - (int)err.column -
|
||||||
(int)err.length+1,
|
(int)err.length + 1,
|
||||||
line_starts + (int)err.column + err.length - 1);
|
line_starts + (int)err.column + err.length - 1);
|
||||||
for (int64_t i = 0; i < err.column - 1; i++) {
|
for (int64_t i = 0; i < err.column - 1; i++) {
|
||||||
fprintf(stderr, " ");
|
fprintf(stderr, " ");
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
* 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;
|
||||||
|
|
||||||
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
|
||||||
@@ -39,10 +39,6 @@ uint64_t siphash64_bytes(const void *data, size_t len,const uint8_t hash_key[16]
|
|||||||
uint8_t out[8];
|
uint8_t out[8];
|
||||||
if (siphash(data, len, hash_key, out, sizeof(out)) != 0)
|
if (siphash(data, len, hash_key, out, sizeof(out)) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64_t hash = 0;
|
return *(uint64_t *)out;
|
||||||
for (int i = 0; i < 8; ++i)
|
|
||||||
hash |= ((uint64_t)out[i]) << (8 * i);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
482
src/import.c
Normal file
482
src/import.c
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
#include "../external/cwalk/include/cwalk.h"
|
||||||
|
#include "../external/xxhash/xxhash.h"
|
||||||
|
#include "arobject.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "hash_data/hash_data.h"
|
||||||
|
#include "hashmap/hashmap.h"
|
||||||
|
#include "lexer/lexer.h"
|
||||||
|
#include "lexer/token.h"
|
||||||
|
#include "runtime/internals/hashmap/hashmap.h"
|
||||||
|
#include "runtime/runtime.h"
|
||||||
|
#include "translator/translator.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h> // for _mkdir
|
||||||
|
#include <sys/stat.h> // for _stat
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include "err.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
// Windows / MinGW usually uses little-endian, so these can be no-ops
|
||||||
|
// But define them explicitly to avoid implicit declaration warnings
|
||||||
|
|
||||||
|
static inline uint32_t le32toh(uint32_t x) { return x; }
|
||||||
|
static inline uint64_t le64toh(uint64_t x) { return x; }
|
||||||
|
static inline uint32_t htole32(uint32_t x) { return x; }
|
||||||
|
static inline uint64_t htole64(uint64_t x) { return x; }
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <endian.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int is_regular_file(const char *path) {
|
||||||
|
struct stat path_stat;
|
||||||
|
stat(path, &path_stat);
|
||||||
|
return S_ISREG(path_stat.st_mode);
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <libkern/OSByteOrder.h>
|
||||||
|
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||||
|
#define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||||
|
#define htole64(x) OSSwapHostToLittleInt64(x)
|
||||||
|
#define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||||
|
// Add others as needed
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/endian.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ensure_dir_exists(const char *path) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
struct _stat st;
|
||||||
|
if (_stat(path, &st) != 0) {
|
||||||
|
// Directory does not exist, create it
|
||||||
|
if (_mkdir(path) != 0) {
|
||||||
|
perror("_mkdir failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (!(st.st_mode & _S_IFDIR)) {
|
||||||
|
fprintf(stderr, "Path exists but is not a directory\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) != 0) {
|
||||||
|
// Directory does not exist, create it
|
||||||
|
if (mkdir(path, 0755) != 0) {
|
||||||
|
perror("mkdir failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
fprintf(stderr, "Path exists but is not a directory\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *CWD;
|
||||||
|
|
||||||
|
const char CACHE_FOLDER[] = "__arcache__";
|
||||||
|
const char FILE_IDENTIFIER[5] = "ARBI";
|
||||||
|
const char BYTECODE_EXTENTION[] = "arbin";
|
||||||
|
const uint32_t version_number = 0;
|
||||||
|
const char version_string[] = "4.0.0";
|
||||||
|
|
||||||
|
bool file_exists(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) == 0) {
|
||||||
|
return S_ISREG(st.st_mode); // true only if it's a regular file
|
||||||
|
}
|
||||||
|
return false; // doesn't exist, or stat failed
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void write_and_hash(FILE *file, XXH64_state_t *state,
|
||||||
|
const void *ptr, size_t size, size_t count) {
|
||||||
|
fwrite(ptr, size, count, file);
|
||||||
|
XXH64_update(state, ptr, size * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void update_hash_from_file(FILE *file, XXH64_state_t *state,
|
||||||
|
size_t size) {
|
||||||
|
char buffer[4096];
|
||||||
|
size_t bytes_read;
|
||||||
|
size_t remaining = size;
|
||||||
|
|
||||||
|
while (remaining > 0 &&
|
||||||
|
(bytes_read =
|
||||||
|
fread(buffer, 1,
|
||||||
|
remaining > sizeof(buffer) ? sizeof(buffer) : remaining,
|
||||||
|
file)) > 0) {
|
||||||
|
XXH64_update(state, buffer, bytes_read);
|
||||||
|
remaining -= bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash,
|
||||||
|
char *source_path) {
|
||||||
|
FILE *bytecode_file = fopen(joined_paths, "rb");
|
||||||
|
if (!bytecode_file) {
|
||||||
|
fprintf(stderr, "cache doesnt exist... compiling from source.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find file size
|
||||||
|
fseek(bytecode_file, 0, SEEK_END);
|
||||||
|
long file_size = ftell(bytecode_file);
|
||||||
|
if (file_size < (long)sizeof(uint64_t)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
fseek(bytecode_file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
// Footer is the last 8 bytes
|
||||||
|
long data_size = file_size - sizeof(uint64_t);
|
||||||
|
|
||||||
|
// Set up hash state
|
||||||
|
XXH64_state_t *state = XXH64_createState();
|
||||||
|
XXH64_reset(state, 0);
|
||||||
|
|
||||||
|
// Hash everything except last 8 bytes
|
||||||
|
update_hash_from_file(bytecode_file, state, data_size);
|
||||||
|
|
||||||
|
// Read stored footer hash
|
||||||
|
uint64_t stored_hash_le;
|
||||||
|
if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) !=
|
||||||
|
sizeof(stored_hash_le)) {
|
||||||
|
XXH64_freeState(state);
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
uint64_t stored_hash = le64toh(stored_hash_le);
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
uint64_t calc_hash = XXH64_digest(state);
|
||||||
|
XXH64_freeState(state);
|
||||||
|
|
||||||
|
if (calc_hash != stored_hash) {
|
||||||
|
fprintf(stderr, "cache hash mismatch (corrupted?)\n");
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now actually parse the file contents
|
||||||
|
fseek(bytecode_file, 0, SEEK_SET); // rewind to start
|
||||||
|
|
||||||
|
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
|
||||||
|
if (fread(&file_identifier_from_cache, 1,
|
||||||
|
sizeof(file_identifier_from_cache) - 1,
|
||||||
|
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
|
||||||
|
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
|
||||||
|
sizeof(file_identifier_from_cache)) != 0) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read_version;
|
||||||
|
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
|
||||||
|
sizeof(read_version)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
read_version = le32toh(read_version);
|
||||||
|
|
||||||
|
if (read_version != version_number) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t read_hash;
|
||||||
|
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
|
||||||
|
sizeof(read_hash)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
read_hash = le64toh(read_hash);
|
||||||
|
|
||||||
|
if (read_hash != hash) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t register_count;
|
||||||
|
if (fread(®ister_count, 1, sizeof(register_count), bytecode_file) !=
|
||||||
|
sizeof(register_count)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t constantsSize;
|
||||||
|
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
|
||||||
|
sizeof(constantsSize)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
constantsSize = le64toh(constantsSize);
|
||||||
|
|
||||||
|
uint64_t bytecodeSize;
|
||||||
|
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
|
||||||
|
sizeof(bytecodeSize)) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
bytecodeSize = le64toh(bytecodeSize);
|
||||||
|
|
||||||
|
*translated_dest = init_translator(source_path);
|
||||||
|
|
||||||
|
translated_dest->registerCount = register_count;
|
||||||
|
|
||||||
|
arena_resize(&translated_dest->constants, constantsSize);
|
||||||
|
|
||||||
|
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
|
||||||
|
constantsSize) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
translated_dest->constants.size = constantsSize;
|
||||||
|
|
||||||
|
darray_resize(&translated_dest->bytecode, bytecodeSize);
|
||||||
|
|
||||||
|
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
|
||||||
|
bytecodeSize) {
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
translated_dest->bytecode.size = bytecodeSize;
|
||||||
|
|
||||||
|
fprintf(stderr, "cache exists and is valid, so will be used.\n");
|
||||||
|
fclose(bytecode_file);
|
||||||
|
return 0;
|
||||||
|
FAILED:
|
||||||
|
fprintf(stderr, "cache is invalid... compiling from source.\n");
|
||||||
|
fclose(bytecode_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Translated load_argon_file(char *path, ArErr *err) {
|
||||||
|
clock_t start, end;
|
||||||
|
clock_t beginning = clock();
|
||||||
|
double time_spent, total_time_spent = 0;
|
||||||
|
|
||||||
|
const char *basename_ptr;
|
||||||
|
size_t basename_length;
|
||||||
|
cwk_path_get_basename(path, &basename_ptr, &basename_length);
|
||||||
|
|
||||||
|
if (!basename_ptr) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "Path Error", "path has no basename '%s'",
|
||||||
|
path);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
|
||||||
|
char basename[FILENAME_MAX];
|
||||||
|
memcpy(basename, basename_ptr, basename_length);
|
||||||
|
|
||||||
|
size_t parent_directory_length;
|
||||||
|
cwk_path_get_dirname(path, &parent_directory_length);
|
||||||
|
|
||||||
|
char parent_directory[FILENAME_MAX];
|
||||||
|
memcpy(parent_directory, path, parent_directory_length);
|
||||||
|
parent_directory[parent_directory_length] = '\0';
|
||||||
|
|
||||||
|
char cache_folder_path[FILENAME_MAX];
|
||||||
|
cwk_path_join(parent_directory, CACHE_FOLDER, cache_folder_path,
|
||||||
|
sizeof(cache_folder_path));
|
||||||
|
|
||||||
|
char cache_file_path[FILENAME_MAX];
|
||||||
|
cwk_path_join(cache_folder_path, basename, cache_file_path,
|
||||||
|
sizeof(cache_file_path));
|
||||||
|
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION,
|
||||||
|
cache_file_path, sizeof(cache_file_path));
|
||||||
|
FILE *file = fopen(path, "r");
|
||||||
|
if (!file) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to open file '%s'",
|
||||||
|
path);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH3_state_t *hash_state = XXH3_createState();
|
||||||
|
XXH3_64bits_reset(hash_state);
|
||||||
|
|
||||||
|
char buffer[8192];
|
||||||
|
size_t bytes;
|
||||||
|
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) {
|
||||||
|
XXH3_64bits_update(hash_state, buffer, bytes);
|
||||||
|
}
|
||||||
|
rewind(file);
|
||||||
|
uint64_t hash = XXH3_64bits_digest(hash_state);
|
||||||
|
XXH3_freeState(hash_state);
|
||||||
|
|
||||||
|
Translated translated;
|
||||||
|
|
||||||
|
if (load_cache(&translated, cache_file_path, hash, path) != 0) {
|
||||||
|
|
||||||
|
DArray tokens;
|
||||||
|
darray_init(&tokens, sizeof(Token));
|
||||||
|
|
||||||
|
LexerState state = {path, file, 0, 0, &tokens};
|
||||||
|
start = clock();
|
||||||
|
*err = lexer(state);
|
||||||
|
if (err->exists) {
|
||||||
|
darray_free(&tokens, free_token);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Lexer time taken: %f seconds\n", time_spent);
|
||||||
|
fclose(state.file);
|
||||||
|
|
||||||
|
DArray ast;
|
||||||
|
|
||||||
|
darray_init(&ast, sizeof(ParsedValue));
|
||||||
|
|
||||||
|
start = clock();
|
||||||
|
*err = parser(path, &ast, &tokens, false);
|
||||||
|
darray_free(&tokens, free_token);
|
||||||
|
if (err->exists) {
|
||||||
|
darray_free(&ast, free_parsed);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Parser time taken: %f seconds\n", time_spent);
|
||||||
|
|
||||||
|
start = clock();
|
||||||
|
|
||||||
|
translated = init_translator(path);
|
||||||
|
*err = translate(&translated, &ast);
|
||||||
|
darray_free(&ast, free_parsed);
|
||||||
|
if (err->exists) {
|
||||||
|
darray_free(&translated.bytecode, NULL);
|
||||||
|
free(translated.constants.data);
|
||||||
|
hashmap_free(translated.constants.hashmap, NULL);
|
||||||
|
return (Translated){};
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Translation time taken: %f seconds\n", time_spent);
|
||||||
|
#if defined(__linux__)
|
||||||
|
malloc_trim(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ensure_dir_exists(cache_folder_path);
|
||||||
|
|
||||||
|
file = fopen(cache_file_path, "wb");
|
||||||
|
|
||||||
|
uint64_t constantsSize = translated.constants.size;
|
||||||
|
uint64_t bytecodeSize = translated.bytecode.size;
|
||||||
|
|
||||||
|
uint32_t version_number_htole32ed = htole32(version_number);
|
||||||
|
uint64_t net_hash = htole64(hash);
|
||||||
|
constantsSize = htole64(constantsSize);
|
||||||
|
bytecodeSize = htole64(bytecodeSize);
|
||||||
|
|
||||||
|
XXH64_state_t *hash_state = XXH64_createState();
|
||||||
|
XXH64_reset(hash_state, 0);
|
||||||
|
|
||||||
|
write_and_hash(file, hash_state, &FILE_IDENTIFIER, sizeof(char),
|
||||||
|
strlen(FILE_IDENTIFIER));
|
||||||
|
write_and_hash(file, hash_state, &version_number_htole32ed,
|
||||||
|
sizeof(uint32_t), 1);
|
||||||
|
write_and_hash(file, hash_state, &net_hash, sizeof(net_hash), 1);
|
||||||
|
write_and_hash(file, hash_state, &translated.registerCount, sizeof(uint8_t),
|
||||||
|
1);
|
||||||
|
write_and_hash(file, hash_state, &constantsSize, sizeof(uint64_t), 1);
|
||||||
|
write_and_hash(file, hash_state, &bytecodeSize, sizeof(uint64_t), 1);
|
||||||
|
write_and_hash(file, hash_state, translated.constants.data, 1,
|
||||||
|
translated.constants.size);
|
||||||
|
write_and_hash(file, hash_state, translated.bytecode.data,
|
||||||
|
translated.bytecode.element_size, translated.bytecode.size);
|
||||||
|
|
||||||
|
// Finalize the hash
|
||||||
|
uint64_t file_hash = XXH64_digest(hash_state);
|
||||||
|
XXH64_freeState(hash_state);
|
||||||
|
|
||||||
|
// Convert to little-endian before writing if needed
|
||||||
|
uint64_t file_hash_le = htole64(file_hash);
|
||||||
|
fwrite(&file_hash_le, sizeof(file_hash_le), 1, file);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
hashmap_free(translated.constants.hashmap, NULL);
|
||||||
|
Translated gc_translated = {
|
||||||
|
translated.registerCount, translated.registerAssignment, NULL, {}, {},
|
||||||
|
translated.path};
|
||||||
|
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity +
|
||||||
|
translated.constants.capacity);
|
||||||
|
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
||||||
|
translated.bytecode.capacity);
|
||||||
|
gc_translated.bytecode.element_size = translated.bytecode.element_size;
|
||||||
|
gc_translated.bytecode.size = translated.bytecode.size;
|
||||||
|
gc_translated.bytecode.resizable = false;
|
||||||
|
gc_translated.bytecode.capacity =
|
||||||
|
translated.bytecode.size * translated.bytecode.element_size;
|
||||||
|
gc_translated.constants.data =
|
||||||
|
gc_translated.bytecode.data + translated.bytecode.capacity;
|
||||||
|
memcpy(gc_translated.constants.data, translated.constants.data,
|
||||||
|
translated.constants.capacity);
|
||||||
|
gc_translated.constants.size = translated.constants.size;
|
||||||
|
gc_translated.constants.capacity = translated.constants.capacity;
|
||||||
|
free(translated.bytecode.data);
|
||||||
|
free(translated.constants.data);
|
||||||
|
total_time_spent = (double)(clock() - beginning) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "total time taken loading file (%s): %f seconds\n", path,
|
||||||
|
total_time_spent);
|
||||||
|
return gc_translated;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *PRE_PATHS_TO_TEST[] = {"", "", "argon_modules", "argon_modules"};
|
||||||
|
const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST) / sizeof(char *)] = {
|
||||||
|
"", "init.ar", "", "init.ar"};
|
||||||
|
|
||||||
|
struct hashmap *importing_hash_table = NULL;
|
||||||
|
struct hashmap_GC *imported_hash_table = NULL;
|
||||||
|
|
||||||
|
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||||
|
char path[FILENAME_MAX];
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST) / sizeof(char *); i++) {
|
||||||
|
cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path,
|
||||||
|
sizeof(path));
|
||||||
|
cwk_path_get_absolute(path, path_relative, path, sizeof(path));
|
||||||
|
cwk_path_get_absolute(path, POST_PATHS_TO_TEST[i], path, sizeof(path));
|
||||||
|
if (file_exists(path)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to find file '%s'",
|
||||||
|
path_relative);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!importing_hash_table)
|
||||||
|
importing_hash_table = createHashmap();
|
||||||
|
uint64_t hash = siphash64_bytes(path, strlen(path), siphash_key);
|
||||||
|
hashmap_insert(importing_hash_table, hash, path, (void *)true, 0);
|
||||||
|
Translated translated = load_argon_file(path, err);
|
||||||
|
if (err->exists) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
clock_t start = clock(), end;
|
||||||
|
RuntimeState state = init_runtime_state(translated, path);
|
||||||
|
Stack *main_scope = create_scope(Global_Scope, true);
|
||||||
|
runtime(translated, state, main_scope, err);
|
||||||
|
if (err->exists) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||||
|
fprintf(stderr, "Execution time taken: %f seconds\n", time_spent);
|
||||||
|
hashmap_insert(importing_hash_table, hash, path, (void *)false, 0);
|
||||||
|
if (!imported_hash_table)
|
||||||
|
imported_hash_table = createHashmap_GC();
|
||||||
|
hashmap_insert_GC(imported_hash_table, hash, path, main_scope, 0);
|
||||||
|
return main_scope;
|
||||||
|
}
|
||||||
17
src/import.h
Normal file
17
src/import.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMPORT_H
|
||||||
|
#define IMPORT_H
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
extern char*CWD;
|
||||||
|
|
||||||
|
extern const char version_string[];
|
||||||
|
|
||||||
|
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err);
|
||||||
|
|
||||||
|
#endif // IMPORT_H
|
||||||
@@ -32,13 +32,6 @@ int yywrap(void * unused_param) {
|
|||||||
":" { return TOKEN_COLON; }
|
":" { return TOKEN_COLON; }
|
||||||
|
|
||||||
"=" { return TOKEN_ASSIGN; }
|
"=" { return TOKEN_ASSIGN; }
|
||||||
"+=" { return TOKEN_ASSIGN_PLUS; }
|
|
||||||
"-=" { return TOKEN_ASSIGN_MINUS; }
|
|
||||||
"//=" { return TOKEN_ASSIGN_FLOORDIV; }
|
|
||||||
"/=" { return TOKEN_ASSIGN_SLASH; }
|
|
||||||
"%=" { return TOKEN_ASSIGN_MODULO; }
|
|
||||||
"*=" { return TOKEN_ASSIGN_STAR; }
|
|
||||||
"^=" { return TOKEN_ASSIGN_CARET; }
|
|
||||||
|
|
||||||
"not"[ \t]+"in" { return TOKEN_NOT_IN; }
|
"not"[ \t]+"in" { return TOKEN_NOT_IN; }
|
||||||
"in" { return TOKEN_IN; }
|
"in" { return TOKEN_IN; }
|
||||||
|
|||||||
@@ -17,13 +17,6 @@ typedef enum {
|
|||||||
TOKEN_INDENT,
|
TOKEN_INDENT,
|
||||||
|
|
||||||
TOKEN_ASSIGN,
|
TOKEN_ASSIGN,
|
||||||
TOKEN_ASSIGN_PLUS,
|
|
||||||
TOKEN_ASSIGN_MINUS,
|
|
||||||
TOKEN_ASSIGN_FLOORDIV,
|
|
||||||
TOKEN_ASSIGN_SLASH,
|
|
||||||
TOKEN_ASSIGN_MODULO,
|
|
||||||
TOKEN_ASSIGN_STAR,
|
|
||||||
TOKEN_ASSIGN_CARET,
|
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
TOKEN_CARET, // ^ (Exponentiation)
|
TOKEN_CARET, // ^ (Exponentiation)
|
||||||
@@ -31,8 +24,8 @@ typedef enum {
|
|||||||
TOKEN_SLASH, // / (Division)
|
TOKEN_SLASH, // / (Division)
|
||||||
TOKEN_FLOORDIV, // // (Floor Division)
|
TOKEN_FLOORDIV, // // (Floor Division)
|
||||||
TOKEN_MODULO, // % (Modulo)
|
TOKEN_MODULO, // % (Modulo)
|
||||||
TOKEN_PLUS, // + (Addition)
|
|
||||||
TOKEN_MINUS, // - (Subtraction)
|
TOKEN_MINUS, // - (Subtraction)
|
||||||
|
TOKEN_PLUS, // + (Addition)
|
||||||
TOKEN_LT, // <
|
TOKEN_LT, // <
|
||||||
TOKEN_GT, // >
|
TOKEN_GT, // >
|
||||||
TOKEN_LE, // <=
|
TOKEN_LE, // <=
|
||||||
|
|||||||
428
src/main.c
428
src/main.c
@@ -4,73 +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 "returnTypes.h"
|
|
||||||
#include "shell.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
|
|
||||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/endian.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *get_current_directory() {
|
char *get_current_directory() {
|
||||||
@@ -101,383 +51,25 @@ char *get_current_directory() {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ensure_dir_exists(const char *path) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
struct _stat st;
|
|
||||||
if (_stat(path, &st) != 0) {
|
|
||||||
// Directory does not exist, create it
|
|
||||||
if (_mkdir(path) != 0) {
|
|
||||||
perror("_mkdir failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (!(st.st_mode & _S_IFDIR)) {
|
|
||||||
fprintf(stderr, "Path exists but is not a directory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
struct stat st;
|
|
||||||
if (stat(path, &st) != 0) {
|
|
||||||
// Directory does not exist, create it
|
|
||||||
if (mkdir(path, 0755) != 0) {
|
|
||||||
perror("mkdir failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (!S_ISDIR(st.st_mode)) {
|
|
||||||
fprintf(stderr, "Path exists but is not a directory\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void write_and_hash(FILE *file, XXH64_state_t *state,
|
|
||||||
const void *ptr, size_t size, size_t count) {
|
|
||||||
fwrite(ptr, size, count, file);
|
|
||||||
XXH64_update(state, ptr, size * count);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void update_hash_from_file(FILE *file, XXH64_state_t *state,
|
|
||||||
size_t size) {
|
|
||||||
char buffer[4096];
|
|
||||||
size_t bytes_read;
|
|
||||||
size_t remaining = size;
|
|
||||||
|
|
||||||
while (remaining > 0 &&
|
|
||||||
(bytes_read =
|
|
||||||
fread(buffer, 1,
|
|
||||||
remaining > sizeof(buffer) ? sizeof(buffer) : remaining,
|
|
||||||
file)) > 0) {
|
|
||||||
XXH64_update(state, buffer, bytes_read);
|
|
||||||
remaining -= bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char CACHE_FOLDER[] = "__arcache__";
|
|
||||||
const char FILE_IDENTIFIER[5] = "ARBI";
|
|
||||||
const char BYTECODE_EXTENTION[] = "arbin";
|
|
||||||
const uint32_t version_number = 0;
|
|
||||||
|
|
||||||
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash,
|
|
||||||
char *source_path) {
|
|
||||||
FILE *bytecode_file = fopen(joined_paths, "rb");
|
|
||||||
if (!bytecode_file) {
|
|
||||||
fprintf(stderr, "cache doesnt exist... compiling from source.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find file size
|
|
||||||
fseek(bytecode_file, 0, SEEK_END);
|
|
||||||
long file_size = ftell(bytecode_file);
|
|
||||||
if (file_size < (long)sizeof(uint64_t)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
fseek(bytecode_file, 0, SEEK_SET);
|
|
||||||
|
|
||||||
// Footer is the last 8 bytes
|
|
||||||
long data_size = file_size - sizeof(uint64_t);
|
|
||||||
|
|
||||||
// Set up hash state
|
|
||||||
XXH64_state_t *state = XXH64_createState();
|
|
||||||
XXH64_reset(state, 0);
|
|
||||||
|
|
||||||
// Hash everything except last 8 bytes
|
|
||||||
update_hash_from_file(bytecode_file, state, data_size);
|
|
||||||
|
|
||||||
// Read stored footer hash
|
|
||||||
uint64_t stored_hash_le;
|
|
||||||
if (fread(&stored_hash_le, 1, sizeof(stored_hash_le), bytecode_file) !=
|
|
||||||
sizeof(stored_hash_le)) {
|
|
||||||
XXH64_freeState(state);
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
uint64_t stored_hash = le64toh(stored_hash_le);
|
|
||||||
|
|
||||||
// Compare
|
|
||||||
uint64_t calc_hash = XXH64_digest(state);
|
|
||||||
XXH64_freeState(state);
|
|
||||||
|
|
||||||
if (calc_hash != stored_hash) {
|
|
||||||
fprintf(stderr, "cache hash mismatch (corrupted?)\n");
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now actually parse the file contents
|
|
||||||
fseek(bytecode_file, 0, SEEK_SET); // rewind to start
|
|
||||||
|
|
||||||
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
|
|
||||||
if (fread(&file_identifier_from_cache, 1,
|
|
||||||
sizeof(file_identifier_from_cache) - 1,
|
|
||||||
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
|
|
||||||
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
|
|
||||||
sizeof(file_identifier_from_cache)) != 0) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t read_version;
|
|
||||||
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
|
|
||||||
sizeof(read_version)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
read_version = le32toh(read_version);
|
|
||||||
|
|
||||||
if (read_version != version_number) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t read_hash;
|
|
||||||
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
|
|
||||||
sizeof(read_hash)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
read_hash = le64toh(read_hash);
|
|
||||||
|
|
||||||
if (read_hash != hash) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t register_count;
|
|
||||||
if (fread(®ister_count, 1, sizeof(register_count), bytecode_file) !=
|
|
||||||
sizeof(register_count)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t constantsSize;
|
|
||||||
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
|
|
||||||
sizeof(constantsSize)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
constantsSize = le64toh(constantsSize);
|
|
||||||
|
|
||||||
uint64_t bytecodeSize;
|
|
||||||
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
|
|
||||||
sizeof(bytecodeSize)) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
bytecodeSize = le64toh(bytecodeSize);
|
|
||||||
|
|
||||||
*translated_dest = init_translator(source_path);
|
|
||||||
|
|
||||||
arena_resize(&translated_dest->constants, constantsSize);
|
|
||||||
|
|
||||||
if (fread(translated_dest->constants.data, 1, constantsSize, bytecode_file) !=
|
|
||||||
constantsSize) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
darray_resize(&translated_dest->bytecode, bytecodeSize);
|
|
||||||
|
|
||||||
if (fread(translated_dest->bytecode.data, 1, bytecodeSize, bytecode_file) !=
|
|
||||||
bytecodeSize) {
|
|
||||||
goto FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "cache exists and is valid, so will be used.\n");
|
|
||||||
fclose(bytecode_file);
|
|
||||||
return 0;
|
|
||||||
FAILED:
|
|
||||||
fprintf(stderr, "cache is invalid... compiling from source.\n");
|
|
||||||
fclose(bytecode_file);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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, 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);
|
|
||||||
total_time_spent = (double)(clock() - beginning) / CLOCKS_PER_SEC;
|
|
||||||
fprintf(stderr, "total time taken loading file (%s): %f seconds\n", path,
|
|
||||||
total_time_spent);
|
|
||||||
return gc_translated;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
ar_memory_init();
|
ar_memory_init();
|
||||||
|
|
||||||
generate_siphash_key(siphash_key);
|
generate_siphash_key(siphash_key);
|
||||||
|
init_built_in_field_hashes();
|
||||||
bootstrap_types();
|
bootstrap_types();
|
||||||
bootstrap_globals();
|
bootstrap_globals();
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
return shell();
|
return shell();
|
||||||
char *CWD = get_current_directory();
|
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);
|
||||||
free(CWD);
|
|
||||||
ArErr err;
|
|
||||||
Translated translated = load_argon_file(path, &err);
|
|
||||||
if (err.exists) {
|
if (err.exists) {
|
||||||
output_err(err);
|
output_err(err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
clock_t start = clock(), end;
|
free(CWD);
|
||||||
RuntimeState state = init_runtime_state(translated, path);
|
ar_memory_shutdown();
|
||||||
Stack *main_scope = create_scope(Global_Scope);
|
|
||||||
err = runtime(translated, state, main_scope);
|
|
||||||
|
|
||||||
end = clock();
|
|
||||||
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
|
||||||
fprintf(stderr, "Execution time taken: %f seconds\n", time_spent);
|
|
||||||
|
|
||||||
if (runtime_hash_table)
|
if (runtime_hash_table)
|
||||||
hashmap_free(runtime_hash_table, NULL);
|
hashmap_free(runtime_hash_table, NULL);
|
||||||
if (err.exists) {
|
if (err.exists) {
|
||||||
|
|||||||
51
src/memory.c
51
src/memory.c
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include <gc.h>
|
#include <gc.h>
|
||||||
#include <gmp.h>
|
#include <pthread.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> // for malloc/free (temp arena fallback)
|
#include <stdlib.h> // for malloc/free (temp arena fallback)
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -20,24 +21,52 @@ void *checked_malloc(size_t size) {
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *gmp_gc_realloc(void *ptr, size_t old_size, size_t new_size) {
|
void *checked_realloc(void *ptr, size_t size) {
|
||||||
(void)old_size; // Ignore old_size, Boehm doesn't need it
|
void *new_ptr = realloc(ptr, size);
|
||||||
return GC_realloc(ptr, new_size);
|
if (!new_ptr) {
|
||||||
|
fprintf(stderr, "fatal error: failed to allocate %zu bytes\n", size);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gmp_gc_free(void *ptr, size_t size) {
|
struct allocation *memory_allocations = NULL;
|
||||||
(void)size; // Boehm GC manages this itself
|
size_t memory_allocations_size = 0;
|
||||||
// No-op — memory will be collected automatically
|
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
GC_FREE(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ar_memory_init() {
|
void ar_memory_init() {
|
||||||
GC_INIT();
|
GC_INIT();
|
||||||
|
// memory_allocations_size = 8;
|
||||||
|
// memory_allocations = malloc(memory_allocations_size*sizeof(struct
|
||||||
|
// allocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ar_alloc(size_t size) { return GC_MALLOC(size); }
|
void ar_memory_shutdown() {
|
||||||
|
// for (size_t i = 0; i<memory_allocations_size;i++) {
|
||||||
|
// if (memory_allocations[i].status != allocation_fully_freed) {
|
||||||
|
// free(memory_allocations[i].ptr);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// free(memory_allocations);
|
||||||
|
}
|
||||||
|
|
||||||
void *ar_realloc(void *old, size_t size) { return GC_REALLOC(old, 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) {
|
||||||
|
void *ptr = GC_REALLOC(old, size);
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr, "panic: unable to allocate memory\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
||||||
GC_finalization_proc *old_fn, void **old_client_data) {
|
GC_finalization_proc *old_fn, void **old_client_data) {
|
||||||
|
|||||||
17
src/memory.h
17
src/memory.h
@@ -8,10 +8,23 @@
|
|||||||
#define ARGON_MEMORY_H
|
#define ARGON_MEMORY_H
|
||||||
|
|
||||||
#include <stddef.h> // for size_t
|
#include <stddef.h> // for size_t
|
||||||
#include <gc/gc.h>
|
#include <stdbool.h>
|
||||||
|
#include <gc.h>
|
||||||
|
|
||||||
// GC-managed allocations
|
// GC-managed allocations
|
||||||
|
|
||||||
|
typedef enum allocation_status {
|
||||||
|
allocation_used,
|
||||||
|
allocation_soft_free, // avaiable for use, since it hasnt been freed but isnt in use.
|
||||||
|
allocation_fully_freed,
|
||||||
|
} allocation_status;
|
||||||
|
|
||||||
|
struct allocation {
|
||||||
|
void*ptr;
|
||||||
|
size_t size;
|
||||||
|
allocation_status status;
|
||||||
|
};
|
||||||
|
|
||||||
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
|
||||||
GC_finalization_proc *old_fn, void **old_client_data);
|
GC_finalization_proc *old_fn, void **old_client_data);
|
||||||
void *ar_alloc(size_t size);
|
void *ar_alloc(size_t size);
|
||||||
@@ -21,7 +34,9 @@ char *ar_strdup(const char *str);
|
|||||||
|
|
||||||
// Memory init/shutdown
|
// Memory init/shutdown
|
||||||
void ar_memory_init();
|
void ar_memory_init();
|
||||||
|
void ar_memory_shutdown();
|
||||||
|
|
||||||
void *checked_malloc(size_t size);
|
void *checked_malloc(size_t size);
|
||||||
|
void *checked_realloc(void *ptr, size_t size);
|
||||||
|
|
||||||
#endif // ARGON_MEMORY_H
|
#endif // ARGON_MEMORY_H
|
||||||
@@ -15,86 +15,38 @@
|
|||||||
|
|
||||||
ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
||||||
ParsedValue *to_access) {
|
ParsedValue *to_access) {
|
||||||
Token *first_token = darray_get(tokens, *index);
|
|
||||||
(*index)++;
|
|
||||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
||||||
parsedAccess->to_access = *to_access;
|
parsedAccess->to_access = to_access;
|
||||||
|
parsedAccess->access = NULL;
|
||||||
parsedValue->type = AST_ACCESS;
|
parsedValue->type = AST_ACCESS;
|
||||||
parsedValue->data = parsedAccess;
|
parsedValue->data = parsedAccess;
|
||||||
free(to_access);
|
(*index)++;
|
||||||
darray_init(&parsedAccess->access, sizeof(ParsedValue));
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
if (first_token->type == TOKEN_DOT) {
|
if (err.exists) {
|
||||||
ArErr err = error_if_finished(file, tokens, index);
|
free_parsed(parsedValue);
|
||||||
if (err.exists) {
|
free(parsedValue);
|
||||||
free_parsed(parsedValue);
|
return (ParsedValueReturn){err, NULL};
|
||||||
free(parsedValue);
|
|
||||||
return (ParsedValueReturn){err, NULL};
|
|
||||||
}
|
|
||||||
Token *token = darray_get(tokens, *index);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
darray_push(&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)++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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)++;
|
(*index)++;
|
||||||
return (ParsedValueReturn){no_err, parsedValue};
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
}
|
}
|
||||||
@@ -102,7 +54,11 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
|||||||
void free_parse_access(void *ptr) {
|
void free_parse_access(void *ptr) {
|
||||||
ParsedValue *parsedValue = ptr;
|
ParsedValue *parsedValue = ptr;
|
||||||
ParsedAccess *parsedAccess = parsedValue->data;
|
ParsedAccess *parsedAccess = parsedValue->data;
|
||||||
free_parsed(&parsedAccess->to_access);
|
free_parsed(parsedAccess->to_access);
|
||||||
darray_free(&parsedAccess->access, free_parsed);
|
free(parsedAccess->to_access);
|
||||||
|
if (parsedAccess->access) {
|
||||||
|
free_parsed(parsedAccess->access);
|
||||||
|
free(parsedAccess->access);
|
||||||
|
}
|
||||||
free(parsedAccess);
|
free(parsedAccess);
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,8 @@
|
|||||||
#include "../../../lexer/token.h" // for Token
|
#include "../../../lexer/token.h" // for Token
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ParsedValue to_access;
|
ParsedValue *to_access;
|
||||||
bool access_fields;
|
ParsedValue *access;
|
||||||
DArray access;
|
|
||||||
size_t line;
|
size_t line;
|
||||||
size_t column;
|
size_t column;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|||||||
@@ -7,25 +7,38 @@
|
|||||||
#include "assign.h"
|
#include "assign.h"
|
||||||
#include "../../../lexer/token.h"
|
#include "../../../lexer/token.h"
|
||||||
#include "../../../memory.h"
|
#include "../../../memory.h"
|
||||||
|
#include "../../function/function.h"
|
||||||
#include "../../parser.h"
|
#include "../../parser.h"
|
||||||
|
#include "../../string/string.h"
|
||||||
|
#include "../access/access.h"
|
||||||
#include "../call/call.h"
|
#include "../call/call.h"
|
||||||
|
#include "../identifier/identifier.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
||||||
ParsedValue *assign_to, size_t *index) {
|
ParsedValue *assign_to, size_t *index) {
|
||||||
Token *token = darray_get(tokens, *index);
|
Token *token = darray_get(tokens, *index);
|
||||||
|
bool is_function = false;
|
||||||
|
char *function_name;
|
||||||
|
bool to_free_function_name = false;
|
||||||
|
DArray function_args;
|
||||||
|
ParsedValue *function_assign_to;
|
||||||
switch (assign_to->type) {
|
switch (assign_to->type) {
|
||||||
case AST_IDENTIFIER:
|
case AST_IDENTIFIER:
|
||||||
case AST_ACCESS:
|
case AST_ACCESS:
|
||||||
break;
|
break;
|
||||||
case AST_CALL:;
|
case AST_CALL:;
|
||||||
ParsedCall *call = assign_to->data;
|
ParsedCall *call = assign_to->data;
|
||||||
|
darray_init(&function_args, sizeof(char *));
|
||||||
for (size_t i = 0; i < call->args.size; i++) {
|
for (size_t i = 0; i < call->args.size; i++) {
|
||||||
if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) {
|
ParsedValue *arg = darray_get(&call->args, i);
|
||||||
|
if (arg->type != AST_IDENTIFIER) {
|
||||||
free_parsed(assign_to);
|
free_parsed(assign_to);
|
||||||
free(assign_to);
|
free(assign_to);
|
||||||
|
darray_free(&function_args, free_parameter);
|
||||||
return (ParsedValueReturn){
|
return (ParsedValueReturn){
|
||||||
create_err(
|
create_err(
|
||||||
token->line, token->column, token->length, file, "Syntax Error",
|
token->line, token->column, token->length, file, "Syntax Error",
|
||||||
@@ -34,6 +47,32 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
|||||||
"only use letters, digits, or _, and can't be keywords."),
|
"only use letters, digits, or _, and can't be keywords."),
|
||||||
NULL};
|
NULL};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *param = strdup(((ParsedIdentifier *)arg->data)->name);
|
||||||
|
darray_push(&function_args, ¶m);
|
||||||
|
}
|
||||||
|
darray_free(&call->args, free_parsed);
|
||||||
|
is_function = true;
|
||||||
|
function_assign_to = call->to_call;
|
||||||
|
switch (function_assign_to->type) {
|
||||||
|
case AST_IDENTIFIER:
|
||||||
|
function_name = ((ParsedIdentifier *)function_assign_to->data)->name;
|
||||||
|
break;
|
||||||
|
case AST_ACCESS:
|
||||||
|
if (((ParsedAccess *)function_assign_to->data)->access->type ==
|
||||||
|
AST_STRING) {
|
||||||
|
ParsedString *name =
|
||||||
|
((ParsedAccess *)function_assign_to->data)->access->data;
|
||||||
|
function_name = checked_malloc(name->length + 1);
|
||||||
|
function_name[name->length] = 0;
|
||||||
|
memcpy(function_name, name->string, name->length);
|
||||||
|
to_free_function_name = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// FALL THROUGH
|
||||||
|
default:
|
||||||
|
function_name = "anonymous";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
@@ -44,35 +83,44 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
|||||||
free(assign_to);
|
free(assign_to);
|
||||||
return (ParsedValueReturn){err, NULL};
|
return (ParsedValueReturn){err, NULL};
|
||||||
}
|
}
|
||||||
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
|
|
||||||
assign->to = assign_to;
|
|
||||||
assign->type = token->type;
|
|
||||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
|
||||||
parsedValue->type = AST_ASSIGN;
|
|
||||||
parsedValue->data = assign;
|
|
||||||
(*index)++;
|
(*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(assign_to);
|
||||||
free(parsedValue);
|
free(assign_to);
|
||||||
return (ParsedValueReturn){err, NULL};
|
return (ParsedValueReturn){err, NULL};
|
||||||
}
|
}
|
||||||
token = darray_get(tokens, *index);
|
token = darray_get(tokens, *index);
|
||||||
ParsedValueReturn from = parse_token(file, tokens, index, true);
|
ParsedValueReturn from = parse_token(file, tokens, index, true);
|
||||||
if (from.err.exists) {
|
if (from.err.exists) {
|
||||||
free_parsed(parsedValue);
|
free_parsed(assign_to);
|
||||||
free(parsedValue);
|
free(assign_to);
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
assign->from = from.value;
|
if (!from.value) {
|
||||||
if (!assign->from) {
|
free_parsed(assign_to);
|
||||||
free_parsed(parsedValue);
|
free(assign_to);
|
||||||
free(parsedValue);
|
|
||||||
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",
|
||||||
"expected body"),
|
"expected body"),
|
||||||
NULL};
|
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));
|
||||||
|
assign->to = assign_to;
|
||||||
|
assign->type = 0;
|
||||||
|
assign->from = NULL;
|
||||||
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
parsedValue->type = AST_ASSIGN;
|
||||||
|
parsedValue->data = assign;
|
||||||
|
assign->from = from.value;
|
||||||
return (ParsedValueReturn){no_err, parsedValue};
|
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
|
||||||
50
src/parser/not/not.c
Normal file
50
src/parser/not/not.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
#include "not.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
#include "../../memory.h"
|
||||||
|
#include "../parser.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index) {
|
||||||
|
bool invert = true;
|
||||||
|
(*index)++;
|
||||||
|
while (tokens->size > *index) {
|
||||||
|
Token *token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_EXCLAMATION) {
|
||||||
|
ParsedValueReturn value =
|
||||||
|
parse_token_full(file, tokens, index, true, false);
|
||||||
|
if (value.err.exists) {
|
||||||
|
return value;
|
||||||
|
} else if (!value.value) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file,
|
||||||
|
"Syntax Error", "expected value"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
ParsedToBool *parsedToBool = checked_malloc(sizeof(ParsedToBool));
|
||||||
|
parsedToBool->value = value.value;
|
||||||
|
parsedToBool->invert = invert;
|
||||||
|
parsedValue->data = parsedToBool;
|
||||||
|
parsedValue->type = AST_TO_BOOL;
|
||||||
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
|
}
|
||||||
|
invert = !invert;
|
||||||
|
(*index)++;
|
||||||
|
}
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_not(void *ptr) {
|
||||||
|
ParsedValue *parsedValue = ptr;
|
||||||
|
ParsedToBool *parsedToBool = parsedValue->data;
|
||||||
|
free_parsed(parsedToBool->value);
|
||||||
|
free(parsedToBool->value);
|
||||||
|
free(parsedToBool);
|
||||||
|
}
|
||||||
20
src/parser/not/not.h
Normal file
20
src/parser/not/not.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NOT_H
|
||||||
|
#define NOT_H
|
||||||
|
#include "../parser.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool invert;
|
||||||
|
ParsedValue*value;
|
||||||
|
} ParsedToBool;
|
||||||
|
|
||||||
|
ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index);
|
||||||
|
|
||||||
|
void free_not(void *ptr);
|
||||||
|
|
||||||
|
#endif // NOT_H
|
||||||
@@ -12,8 +12,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct operation {};
|
|
||||||
|
|
||||||
ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
|
ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
|
||||||
if (to_operate_on->size == 1) {
|
if (to_operate_on->size == 1) {
|
||||||
return *((ParsedValue *)darray_get(to_operate_on, 0));
|
return *((ParsedValue *)darray_get(to_operate_on, 0));
|
||||||
@@ -31,7 +29,9 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
|
|||||||
operation = *current_operation;
|
operation = *current_operation;
|
||||||
darray_init(&positions, sizeof(size_t));
|
darray_init(&positions, sizeof(size_t));
|
||||||
}
|
}
|
||||||
darray_push(&positions, &i);
|
if (operation_type == current_operation->type) {
|
||||||
|
darray_push(&positions, &i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ParsedValue parsedValue;
|
ParsedValue parsedValue;
|
||||||
parsedValue.type = AST_OPERATION;
|
parsedValue.type = AST_OPERATION;
|
||||||
@@ -42,24 +42,22 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) {
|
|||||||
operationStruct->column = operation.column;
|
operationStruct->column = operation.column;
|
||||||
operationStruct->length = operation.length;
|
operationStruct->length = operation.length;
|
||||||
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
|
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
|
||||||
size_t last_position = 0;
|
|
||||||
size_t to_operate_on_last_position = 0;
|
size_t to_operate_on_last_position = 0;
|
||||||
for (size_t i = 0; i < positions.size; i++) {
|
for (size_t i = 0; i < positions.size; i++) {
|
||||||
size_t *position = darray_get(&positions, i);
|
size_t *position = darray_get(&positions, i);
|
||||||
DArray to_operate_on_slice = darray_slice(
|
DArray to_operate_on_slice = darray_slice(
|
||||||
to_operate_on, to_operate_on_last_position, (*position) + 1);
|
to_operate_on, to_operate_on_last_position, (*position) + 1);
|
||||||
DArray operations_slice =
|
DArray operations_slice =
|
||||||
darray_slice(operations, last_position, *position);
|
darray_slice(operations, to_operate_on_last_position, (*position));
|
||||||
ParsedValue result =
|
ParsedValue result =
|
||||||
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
||||||
darray_push(&operationStruct->to_operate_on, &result);
|
darray_push(&operationStruct->to_operate_on, &result);
|
||||||
last_position = (*position);
|
|
||||||
to_operate_on_last_position = (*position) + 1;
|
to_operate_on_last_position = (*position) + 1;
|
||||||
}
|
}
|
||||||
DArray to_operate_on_slice = darray_slice(
|
DArray to_operate_on_slice = darray_slice(
|
||||||
to_operate_on, to_operate_on_last_position, to_operate_on->size);
|
to_operate_on, to_operate_on_last_position, to_operate_on->size);
|
||||||
DArray operations_slice =
|
DArray operations_slice =
|
||||||
darray_slice(operations, last_position, operations->size);
|
darray_slice(operations, to_operate_on_last_position, operations->size);
|
||||||
ParsedValue result =
|
ParsedValue result =
|
||||||
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
convert_to_operation(&to_operate_on_slice, &operations_slice);
|
||||||
darray_push(&operationStruct->to_operate_on, &result);
|
darray_push(&operationStruct->to_operate_on, &result);
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parentheses-and-anonymous-function.h"
|
||||||
|
#include "../../memory.h"
|
||||||
|
#include "../assignable/identifier/identifier.h"
|
||||||
|
#include "../function/function.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index) {
|
||||||
|
(*index)++;
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
// darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
DArray list;
|
||||||
|
darray_init(&list, sizeof(ParsedValue));
|
||||||
|
Token *token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_RPAREN) {
|
||||||
|
while (*index < tokens->size) {
|
||||||
|
ParsedValueReturn parsedItem = parse_token(file, tokens, index, true);
|
||||||
|
if (parsedItem.err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return parsedItem;
|
||||||
|
}
|
||||||
|
darray_push(&list, parsedItem.value);
|
||||||
|
free(parsedItem.value);
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type == TOKEN_RPAREN) {
|
||||||
|
break;
|
||||||
|
} else if (token->type != TOKEN_COMMA) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file,
|
||||||
|
"Syntax Error", "expected comma"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
(*index)++;
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*index)++;
|
||||||
|
if (*index < tokens->size) {
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type == TOKEN_ASSIGN) {
|
||||||
|
(*index)++;
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
DArray parameters;
|
||||||
|
darray_init(¶meters, sizeof(char *));
|
||||||
|
for (size_t i = 0; i < list.size; i++) {
|
||||||
|
ParsedValue *item = darray_get(&list, i);
|
||||||
|
if (item->type != AST_IDENTIFIER) {
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
darray_free(¶meters, free_parameter);
|
||||||
|
return (ParsedValueReturn){
|
||||||
|
create_err(token->line, token->column, token->length, file,
|
||||||
|
"Syntax Error", "expected identifier"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
char *param = strdup(((ParsedIdentifier *)item->data)->name);
|
||||||
|
darray_push(¶meters, ¶m);
|
||||||
|
}
|
||||||
|
darray_free(&list, free_parsed);
|
||||||
|
ParsedValueReturn parsedBody = parse_token(file, tokens, index, true);
|
||||||
|
if (parsedBody.err.exists) {
|
||||||
|
darray_free(¶meters, free_parameter);
|
||||||
|
return parsedBody;
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){
|
||||||
|
no_err,
|
||||||
|
create_parsed_function("anonymous", parameters, parsedBody.value)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (list.size != 1) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected 1 body"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
memcpy(parsedValue, darray_get(&list, 0), sizeof(ParsedValue));
|
||||||
|
darray_free(&list, NULL);
|
||||||
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef parentheses_and_anonymous_function_H
|
||||||
|
#define parentheses_and_anonymous_function_H
|
||||||
|
#include "../parser.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
|
||||||
|
ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index);
|
||||||
|
|
||||||
|
#endif // parentheses_and_anonymous_function_H
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "assignable/assign/assign.h"
|
#include "assignable/assign/assign.h"
|
||||||
#include "assignable/call/call.h"
|
#include "assignable/call/call.h"
|
||||||
#include "assignable/identifier/identifier.h"
|
#include "assignable/identifier/identifier.h"
|
||||||
|
#include "assignable/item/item.h"
|
||||||
#include "declaration/declaration.h"
|
#include "declaration/declaration.h"
|
||||||
#include "dictionary/dictionary.h"
|
#include "dictionary/dictionary.h"
|
||||||
#include "dowrap/dowrap.h"
|
#include "dowrap/dowrap.h"
|
||||||
@@ -20,8 +21,11 @@
|
|||||||
#include "literals/literals.h"
|
#include "literals/literals.h"
|
||||||
#include "number/number.h"
|
#include "number/number.h"
|
||||||
#include "operations/operations.h"
|
#include "operations/operations.h"
|
||||||
|
#include "parentheses-and-anonymous-function/parentheses-and-anonymous-function.h"
|
||||||
#include "return/return.h"
|
#include "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 +34,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 +76,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 +134,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,22 +159,17 @@ 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:
|
||||||
output = parse_call(file, tokens, index, output.value);
|
output = parse_call(file, tokens, index, output.value);
|
||||||
break;
|
break;
|
||||||
case TOKEN_DOT:
|
case TOKEN_DOT:
|
||||||
case TOKEN_LBRACKET:
|
|
||||||
output = parse_access(file, tokens, index, output.value);
|
output = parse_access(file, tokens, index, output.value);
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_LBRACKET:
|
||||||
|
output = parse_item_access(file, tokens, index, output.value);
|
||||||
|
break;
|
||||||
SWITCH_OPERATIONS
|
SWITCH_OPERATIONS
|
||||||
if (process_operations) {
|
if (process_operations) {
|
||||||
output = parse_operations(file, tokens, index, output.value);
|
output = parse_operations(file, tokens, index, output.value);
|
||||||
@@ -195,7 +202,7 @@ ArErr parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) {
|
|||||||
if (expecting_new_line) {
|
if (expecting_new_line) {
|
||||||
Token *token = darray_get(tokens, old_index);
|
Token *token = darray_get(tokens, old_index);
|
||||||
return create_err(token->line, token->column, token->length, file,
|
return create_err(token->line, token->column, token->length, file,
|
||||||
"Syntax Error", "expected new line");
|
"Syntax Error", "invalid syntax");
|
||||||
}
|
}
|
||||||
expecting_new_line = true;
|
expecting_new_line = true;
|
||||||
darray_push(parsed, parsed_code.value);
|
darray_push(parsed, parsed_code.value);
|
||||||
@@ -237,12 +244,18 @@ void free_parsed(void *ptr) {
|
|||||||
case AST_ACCESS:
|
case AST_ACCESS:
|
||||||
free_parse_access(parsed);
|
free_parse_access(parsed);
|
||||||
break;
|
break;
|
||||||
|
case AST_ITEM_ACCESS:
|
||||||
|
free_parse_item_access(parsed);
|
||||||
|
break;
|
||||||
case AST_NULL:
|
case AST_NULL:
|
||||||
case AST_BOOLEAN:
|
case AST_BOOLEAN:
|
||||||
break;
|
break;
|
||||||
case AST_IF:
|
case AST_IF:
|
||||||
free_parsed_if(parsed);
|
free_parsed_if(parsed);
|
||||||
break;
|
break;
|
||||||
|
case AST_WHILE:
|
||||||
|
free_parsed_while(parsed);
|
||||||
|
break;
|
||||||
case AST_OPERATION:
|
case AST_OPERATION:
|
||||||
free_operation(parsed);
|
free_operation(parsed);
|
||||||
break;
|
break;
|
||||||
@@ -261,5 +274,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,7 @@ typedef enum {
|
|||||||
AST_NUMBER,
|
AST_NUMBER,
|
||||||
AST_IF,
|
AST_IF,
|
||||||
AST_ACCESS,
|
AST_ACCESS,
|
||||||
|
AST_ITEM_ACCESS,
|
||||||
AST_CALL,
|
AST_CALL,
|
||||||
AST_DECLARATION,
|
AST_DECLARATION,
|
||||||
AST_NULL,
|
AST_NULL,
|
||||||
@@ -49,7 +50,9 @@ typedef enum {
|
|||||||
AST_LIST,
|
AST_LIST,
|
||||||
AST_DICTIONARY,
|
AST_DICTIONARY,
|
||||||
AST_FUNCTION,
|
AST_FUNCTION,
|
||||||
AST_RETURN
|
AST_RETURN,
|
||||||
|
AST_WHILE,
|
||||||
|
AST_TO_BOOL
|
||||||
} ValueType;
|
} ValueType;
|
||||||
|
|
||||||
extern const char *ValueTypeNames[];
|
extern const char *ValueTypeNames[];
|
||||||
|
|||||||
101
src/parser/while/while.c
Normal file
101
src/parser/while/while.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
#include "while.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
#include "../../memory.h"
|
||||||
|
#include "../parser.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
ParsedValueReturn parse_while(char *file, DArray *tokens, size_t *index) {
|
||||||
|
Token *token = darray_get(tokens, *index);
|
||||||
|
(*index)++;
|
||||||
|
// Parse ( condition )
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_LPAREN) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected '(' after while"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
(*index)++;
|
||||||
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
ParsedValueReturn condition = parse_token(file, tokens, index, true);
|
||||||
|
if (condition.err.exists) {
|
||||||
|
return condition;
|
||||||
|
} else if (!condition.value) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected condition"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
skip_newlines_and_indents(tokens, index);
|
||||||
|
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
if (token->type != TOKEN_RPAREN) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"missing closing ')' in condition"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
(*index)++;
|
||||||
|
err = error_if_finished(file, tokens, index);
|
||||||
|
if (err.exists) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){err, NULL};
|
||||||
|
}
|
||||||
|
// Parse the body
|
||||||
|
ParsedValueReturn parsed_content = parse_token(file, tokens, index, false);
|
||||||
|
|
||||||
|
if (parsed_content.err.exists) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return parsed_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed_content.value) {
|
||||||
|
if (condition.value) {
|
||||||
|
free_parsed(condition.value);
|
||||||
|
free(condition.value);
|
||||||
|
}
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected body"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedValue *Parsedvalue = checked_malloc(sizeof(ParsedValue));
|
||||||
|
Parsedvalue->type = AST_WHILE;
|
||||||
|
ParsedWhile *Parsed_while = checked_malloc(sizeof(ParsedWhile));
|
||||||
|
Parsedvalue->data = Parsed_while;
|
||||||
|
Parsed_while->condition = condition.value;
|
||||||
|
Parsed_while->content = parsed_content.value;
|
||||||
|
return (ParsedValueReturn){no_err, Parsedvalue};
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_parsed_while(void *ptr) {
|
||||||
|
ParsedValue *parsedValue = ptr;
|
||||||
|
ParsedWhile *parsed_while = parsedValue->data;
|
||||||
|
free_parsed(parsed_while->condition);
|
||||||
|
free(parsed_while->condition);
|
||||||
|
free_parsed(parsed_while->content);
|
||||||
|
free(parsed_while->content);
|
||||||
|
free(parsed_while);
|
||||||
|
}
|
||||||
20
src/parser/while/while.h
Normal file
20
src/parser/while/while.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PARSE_WHILE_H
|
||||||
|
#define PARSE_WHILE_H
|
||||||
|
#include "../parser.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ParsedValue * condition;
|
||||||
|
ParsedValue *content;
|
||||||
|
} ParsedWhile;
|
||||||
|
|
||||||
|
ParsedValueReturn parse_while(char *file, DArray *tokens, size_t *index);
|
||||||
|
|
||||||
|
void free_parsed_while(void *ptr);
|
||||||
|
|
||||||
|
#endif // PARSE_WHILE_H
|
||||||
@@ -8,16 +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;
|
||||||
#endif // RETURN_TYPES_
|
#endif // RETURN_TYPES_
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
#include "access.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv,
|
|
||||||
ArErr *err, RuntimeState *state) {
|
|
||||||
(void)state;
|
|
||||||
if (argc != 3) {
|
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
|
||||||
"__get_attr__ expects 3 arguments, got %" PRIu64);
|
|
||||||
return ARGON_NULL;
|
|
||||||
}
|
|
||||||
ArgonObject *to_access = argv[0];
|
|
||||||
bool check_field = argv[1] == ARGON_TRUE;
|
|
||||||
if (check_field) {
|
|
||||||
ArgonObject *access = argv[2];
|
|
||||||
ArgonObject *value = get_field_l(to_access, access->value.as_str.data,
|
|
||||||
access->value.as_str.length, true, false);
|
|
||||||
if (value)
|
|
||||||
return value;
|
|
||||||
ArgonObject *name = get_field_for_class(
|
|
||||||
get_field(to_access, "__class__", false, false), "__name__", to_access);
|
|
||||||
*err = create_err(
|
|
||||||
0, 0, 0, "", "Runtime Error", "'%.*s' object has no attribute '%.*s'",
|
|
||||||
(int)name->value.as_str.length, name->value.as_str.data,
|
|
||||||
(int)access->value.as_str.length, access->value.as_str.data);
|
|
||||||
}
|
|
||||||
return ARGON_NULL;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef runtime_access_H
|
|
||||||
#define runtime_access_H
|
|
||||||
#include "../objects/literals/literals.h"
|
|
||||||
#include "../objects/object.h"
|
|
||||||
#include "../runtime.h"
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv,
|
|
||||||
ArErr *err, RuntimeState *state);
|
|
||||||
|
|
||||||
#endif // runtime_access_H
|
|
||||||
29
src/runtime/assignment/assignment.c
Normal file
29
src/runtime/assignment/assignment.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assignment.h"
|
||||||
|
|
||||||
|
void runtime_assignment(Translated *translated, RuntimeState *state,
|
||||||
|
struct Stack *stack) {
|
||||||
|
int64_t length = pop_bytecode(translated, state);
|
||||||
|
int64_t offset = pop_bytecode(translated, state);
|
||||||
|
int64_t prehash = pop_bytecode(translated, state);
|
||||||
|
int64_t from_register = pop_byte(translated, state);
|
||||||
|
void *data = arena_get(&translated->constants, offset);
|
||||||
|
uint64_t hash = runtime_hash(data, length, prehash);
|
||||||
|
ArgonObject *key = new_string_object(data, length, prehash, hash);
|
||||||
|
for (Stack *current_stack = stack; current_stack;
|
||||||
|
current_stack = current_stack->prev) {
|
||||||
|
ArgonObject *exists = hashmap_lookup_GC(current_stack->scope, hash);
|
||||||
|
if (exists) {
|
||||||
|
hashmap_insert_GC(current_stack->scope, hash, key,
|
||||||
|
state->registers[from_register], 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register],
|
||||||
|
0);
|
||||||
|
}
|
||||||
15
src/runtime/assignment/assignment.h
Normal file
15
src/runtime/assignment/assignment.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef runtime_assignment_H
|
||||||
|
#define runtime_assignment_H
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include "../objects/string/string.h"
|
||||||
|
|
||||||
|
void runtime_assignment(Translated *translated, RuntimeState *state,
|
||||||
|
struct Stack *stack);
|
||||||
|
|
||||||
|
#endif // runtime_assignment_H
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -19,8 +20,8 @@
|
|||||||
#ifndef _WIN32_WINNT
|
#ifndef _WIN32_WINNT
|
||||||
#define _WIN32_WINNT 0x0602
|
#define _WIN32_WINNT 0x0602
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
double get_memory_usage_mb() {
|
double get_memory_usage_mb() {
|
||||||
PROCESS_MEMORY_COUNTERS pmc;
|
PROCESS_MEMORY_COUNTERS pmc;
|
||||||
@@ -75,27 +76,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 *));
|
||||||
@@ -103,64 +103,89 @@ 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);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
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 = {
|
|
||||||
{object->value.argon_fn.translated.registerCount,
|
|
||||||
NULL,
|
|
||||||
{object->value.argon_fn.bytecode, sizeof(uint8_t),
|
|
||||||
object->value.argon_fn.bytecode_length,
|
|
||||||
object->value.argon_fn.bytecode_length, false},
|
|
||||||
object->value.argon_fn.translated.constants,
|
|
||||||
object->value.argon_fn.translated.path},
|
|
||||||
{state->registers,
|
|
||||||
0,
|
|
||||||
object->value.argon_fn.translated.path,
|
|
||||||
NULL,
|
|
||||||
state->currentStackFramePointer,
|
|
||||||
{},
|
|
||||||
{}},
|
|
||||||
scope,
|
|
||||||
*state->currentStackFramePointer,
|
|
||||||
(*state->currentStackFramePointer)->depth + 1};
|
|
||||||
if (CStackFrame) {
|
if (CStackFrame) {
|
||||||
return runtime(new_stackFrame.translated, new_stackFrame.state, new_stackFrame.stack);
|
ArgonObject * registers[MAX_REGISTERS]; // fixed on the stack for speed purposes
|
||||||
} else {
|
StackFrame new_stackFrame = {
|
||||||
if (((*state->currentStackFramePointer)->depth + 1) % STACKFRAME_CHUNKS ==
|
{object->value.argon_fn->translated.registerCount,
|
||||||
0) {
|
object->value.argon_fn->translated.registerAssignment,
|
||||||
*state->currentStackFramePointer =
|
NULL,
|
||||||
ar_alloc(sizeof(StackFrame) * STACKFRAME_CHUNKS);
|
{object->value.argon_fn->bytecode, sizeof(uint8_t),
|
||||||
} else {
|
object->value.argon_fn->bytecode_length,
|
||||||
*state->currentStackFramePointer = *state->currentStackFramePointer + 1;
|
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;
|
||||||
}
|
}
|
||||||
**state->currentStackFramePointer = new_stackFrame;
|
runtime(new_stackFrame.translated, new_stackFrame.state,
|
||||||
|
new_stackFrame.stack, err);
|
||||||
|
state->registers[0] = new_stackFrame.state.registers[0];
|
||||||
|
} else {
|
||||||
|
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame)+object->value.argon_fn->translated.registerCount *
|
||||||
|
sizeof(ArgonObject *));
|
||||||
|
*currentStackFrame = (StackFrame){
|
||||||
|
{object->value.argon_fn->translated.registerCount,
|
||||||
|
object->value.argon_fn->translated.registerAssignment,
|
||||||
|
NULL,
|
||||||
|
{object->value.argon_fn->bytecode, sizeof(uint8_t),
|
||||||
|
object->value.argon_fn->bytecode_length,
|
||||||
|
object->value.argon_fn->bytecode_length, false},
|
||||||
|
object->value.argon_fn->translated.constants,
|
||||||
|
object->value.argon_fn->translated.path},
|
||||||
|
{(ArgonObject **)((char*)currentStackFrame+sizeof(StackFrame)),
|
||||||
|
0,
|
||||||
|
object->value.argon_fn->translated.path,
|
||||||
|
NULL,
|
||||||
|
state->currentStackFramePointer,
|
||||||
|
{},
|
||||||
|
{}},
|
||||||
|
scope,
|
||||||
|
*state->currentStackFramePointer,
|
||||||
|
(*state->currentStackFramePointer)->depth + 1};
|
||||||
|
for (size_t i = 0; i < (*currentStackFrame).translated.registerCount; i++) {
|
||||||
|
(*currentStackFrame).state.registers[i] = NULL;
|
||||||
|
}
|
||||||
|
*state->currentStackFramePointer = currentStackFrame;
|
||||||
if ((*state->currentStackFramePointer)->depth >= 10000) {
|
if ((*state->currentStackFramePointer)->depth >= 10000) {
|
||||||
double logval =
|
double logval =
|
||||||
log10((double)(*state->currentStackFramePointer)->depth);
|
log10((double)(*state->currentStackFramePointer)->depth);
|
||||||
@@ -179,25 +204,23 @@ ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return no_err;
|
return;
|
||||||
}
|
}
|
||||||
} else if (object->type == TYPE_NATIVE_FUNCTION) {
|
} else if (object->type == TYPE_NATIVE_FUNCTION) {
|
||||||
ArErr err = no_err;
|
state->registers[0] = object->value.native_fn(argc, argv, err, state);
|
||||||
state->registers[0] = object->value.native_fn(argc, argv, &err, state);
|
if (err->exists && strlen(err->path) == 0) {
|
||||||
if (err.exists && strlen(err.path) == 0) {
|
err->line = state->source_location.line;
|
||||||
err.line = state->source_location.line;
|
err->column = state->source_location.column;
|
||||||
err.column = state->source_location.column;
|
err->length = state->source_location.length;
|
||||||
err.length = state->source_location.length;
|
strcpy(err->path, state->path);
|
||||||
err.path = state->path;
|
|
||||||
}
|
}
|
||||||
return err;
|
return;
|
||||||
}
|
}
|
||||||
ArgonObject *type_object_name =
|
ArgonObject *type_object_name = get_builtin_field_for_class(
|
||||||
get_field_for_class(get_field(original_object, "__class__", false, false),
|
get_builtin_field(original_object, __class__), __name__, original_object);
|
||||||
"__name__", original_object);
|
*err = create_err(state->source_location.line, state->source_location.column,
|
||||||
return create_err(state->source_location.line, state->source_location.column,
|
|
||||||
state->source_location.length, state->path, "Type Error",
|
state->source_location.length, state->path, "Type Error",
|
||||||
"'%.*s' object is not callable",
|
"'%.*s' object is not callable",
|
||||||
(int)type_object_name->value.as_str.length,
|
(int)type_object_name->value.as_str->length,
|
||||||
type_object_name->value.as_str.data);
|
type_object_name->value.as_str->data);
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
|
ArgonObject *argon_call(ArgonObject *original_object, size_t argc,
|
||||||
ArgonObject **argv, ArErr *err, RuntimeState *state);
|
ArgonObject **argv, ArErr *err, RuntimeState *state);
|
||||||
|
|
||||||
ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
||||||
RuntimeState *state, bool CStackFrame);
|
RuntimeState *state, bool CStackFrame, ArErr *err);
|
||||||
|
|
||||||
#endif // runtime_call_H
|
#endif // runtime_call_H
|
||||||
@@ -6,18 +6,23 @@
|
|||||||
|
|
||||||
#include "declaration.h"
|
#include "declaration.h"
|
||||||
|
|
||||||
ArErr runtime_declaration(Translated *translated, RuntimeState *state,
|
void runtime_declaration(Translated *translated, RuntimeState *state,
|
||||||
struct Stack *stack) {
|
struct Stack *stack, ArErr *err) {
|
||||||
int64_t length = pop_bytecode(translated, state);
|
int64_t length = pop_bytecode(translated, state);
|
||||||
int64_t offset = pop_bytecode(translated, state);
|
int64_t offset = pop_bytecode(translated, state);
|
||||||
int64_t prehash = pop_bytecode(translated, state);
|
int64_t prehash = pop_bytecode(translated, state);
|
||||||
int64_t from_register = pop_byte(translated, state);
|
int64_t from_register = pop_byte(translated, state);
|
||||||
uint64_t hash = runtime_hash(arena_get(&translated->constants, offset), length, prehash);
|
void *data = arena_get(&translated->constants, offset);
|
||||||
ArgonObject * exists = hashmap_lookup_GC(stack->scope, hash);
|
uint64_t hash = runtime_hash(data, length, prehash);
|
||||||
|
ArgonObject *exists = hashmap_lookup_GC(stack->scope, hash);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
return create_err(state->source_location.line, state->source_location.column, state->source_location.length, state->path, "Runtime Error", "Identifier '%.*s' has already been declared in the current scope", length, arena_get(&translated->constants, offset));
|
*err = create_err(
|
||||||
|
state->source_location.line, state->source_location.column,
|
||||||
|
state->source_location.length, state->path, "Runtime Error",
|
||||||
|
"Identifier '%.*s' has already been declared in the current scope",
|
||||||
|
length, arena_get(&translated->constants, offset));
|
||||||
}
|
}
|
||||||
ArgonObject * key = new_string_object(arena_get(&translated->constants, offset), length);
|
ArgonObject *key = new_string_object(data, length, prehash, hash);
|
||||||
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register], 0);
|
hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register],
|
||||||
return no_err;
|
0);
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "../runtime.h"
|
#include "../runtime.h"
|
||||||
#include "../objects/string/string.h"
|
#include "../objects/string/string.h"
|
||||||
|
|
||||||
ArErr runtime_declaration(Translated *translated, RuntimeState *state,
|
void runtime_declaration(Translated *translated, RuntimeState *state,
|
||||||
struct Stack *stack);
|
struct Stack *stack, ArErr *err);
|
||||||
|
|
||||||
#endif // runtime_declaration_H
|
#endif // runtime_declaration_H
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "darray_armem.h"
|
#include "darray_armem.h"
|
||||||
#include "../../../memory.h"
|
#include "../../../memory.h"
|
||||||
#include <gc/gc.h>
|
#include <gc.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|||||||
@@ -7,26 +7,84 @@
|
|||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
|
||||||
#include "../../../memory.h"
|
#include "../../../memory.h"
|
||||||
#include <gc/gc.h>
|
#include <gc.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct hashmap_GC *createHashmap_GC() {
|
struct hashmap_GC *createHashmap_GC() {
|
||||||
size_t size = 8;
|
|
||||||
struct hashmap_GC *t =
|
struct hashmap_GC *t =
|
||||||
(struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
|
(struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
|
||||||
t->size = size;
|
t->size = 0;
|
||||||
t->order = 1;
|
t->order = 1;
|
||||||
t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size);
|
t->list = NULL;
|
||||||
memset(t->list, 0, sizeof(struct node_GC *) * size);
|
t->hashmap_count = 0;
|
||||||
|
t->count = 0;
|
||||||
|
t->inline_count = 0;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int compare_node_asc(const void *a, const void *b) {
|
||||||
|
const struct node_GC *na = *(const struct node_GC **)a;
|
||||||
|
const struct node_GC *nb = *(const struct node_GC **)b;
|
||||||
|
|
||||||
|
// Ascending order (smallest order first)
|
||||||
|
if (na->order < nb->order)
|
||||||
|
return -1;
|
||||||
|
if (na->order > nb->order)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node_GC ** hashmap_GC_to_array(struct hashmap_GC *t,
|
||||||
|
size_t *array_length) {
|
||||||
|
size_t array_size = 8;
|
||||||
|
*array_length = 0;
|
||||||
|
struct node_GC ** array = ar_alloc(array_size * sizeof(struct node_GC*));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < t->inline_count; i++) {
|
||||||
|
if (*array_length >= array_size) {
|
||||||
|
array_size *= 2;
|
||||||
|
array = ar_realloc(array, array_size * sizeof(struct node_GC*));
|
||||||
|
}
|
||||||
|
array[(*array_length)++] = &t->inline_values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < t->size; i++) {
|
||||||
|
struct node_GC *list = t->list[i];
|
||||||
|
struct node_GC *temp = list;
|
||||||
|
while (temp) {
|
||||||
|
if (*array_length >= array_size) {
|
||||||
|
array_size *= 2;
|
||||||
|
array = ar_realloc(array, array_size * sizeof(struct node_GC*));
|
||||||
|
}
|
||||||
|
array[(*array_length)++] = temp;
|
||||||
|
temp = temp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(array, *array_length, sizeof(struct node_GC*), compare_node_asc);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_hashmap_GC(struct hashmap_GC *t) {
|
||||||
|
if (!t->count)
|
||||||
|
return;
|
||||||
|
t->order = 1;
|
||||||
|
t->count = 0;
|
||||||
|
t->inline_count = 0;
|
||||||
|
t->hashmap_count = 0;
|
||||||
|
memset(t->list, 0, sizeof(struct node_GC *) * t->size);
|
||||||
|
}
|
||||||
|
|
||||||
void resize_hashmap_GC(struct hashmap_GC *t) {
|
void resize_hashmap_GC(struct hashmap_GC *t) {
|
||||||
int old_size = t->size;
|
int old_size = t->size;
|
||||||
int new_size = old_size * 2;
|
int new_size = old_size * 2;
|
||||||
|
if (new_size == 0)
|
||||||
|
new_size = 8;
|
||||||
|
|
||||||
struct node_GC **old_list = t->list;
|
struct node_GC **old_list = t->list;
|
||||||
|
|
||||||
@@ -35,8 +93,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 +112,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 +138,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 +146,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 +186,18 @@ void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
|
|||||||
newNode->order = order;
|
newNode->order = order;
|
||||||
newNode->next = list;
|
newNode->next = list;
|
||||||
t->list[pos] = newNode;
|
t->list[pos] = newNode;
|
||||||
|
t->hashmap_count++;
|
||||||
t->count++;
|
t->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) {
|
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) {
|
||||||
|
size_t stop = t->inline_count;
|
||||||
|
for (size_t i = 0; i < stop; i++) {
|
||||||
|
if (t->inline_values[i].hash == hash)
|
||||||
|
return t->inline_values[i].val;
|
||||||
|
}
|
||||||
|
if (!t->list)
|
||||||
|
return NULL;
|
||||||
int pos = hashCode_GC(t, hash);
|
int pos = hashCode_GC(t, hash);
|
||||||
struct node_GC *list = t->list[pos];
|
struct node_GC *list = t->list[pos];
|
||||||
struct node_GC *temp = list;
|
struct node_GC *temp = list;
|
||||||
|
|||||||
@@ -6,9 +6,12 @@
|
|||||||
|
|
||||||
#ifndef HASHMAP_GC_H
|
#ifndef HASHMAP_GC_H
|
||||||
#define HASHMAP_GC_H
|
#define HASHMAP_GC_H
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define INLINE_HASHMAP_ARRAY_SIZE 3
|
||||||
|
|
||||||
struct node_GC {
|
struct node_GC {
|
||||||
uint64_t hash;
|
uint64_t hash;
|
||||||
void *key;
|
void *key;
|
||||||
@@ -18,19 +21,27 @@ struct node_GC {
|
|||||||
};
|
};
|
||||||
struct hashmap_GC {
|
struct hashmap_GC {
|
||||||
size_t size;
|
size_t size;
|
||||||
|
struct node_GC inline_values[INLINE_HASHMAP_ARRAY_SIZE];
|
||||||
size_t count;
|
size_t count;
|
||||||
|
size_t inline_count;
|
||||||
|
size_t hashmap_count;
|
||||||
size_t order;
|
size_t order;
|
||||||
struct node_GC **list;
|
struct node_GC **list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hashmap_GC *createHashmap_GC();
|
struct hashmap_GC *createHashmap_GC();
|
||||||
|
|
||||||
|
void clear_hashmap_GC(struct hashmap_GC *t);
|
||||||
|
|
||||||
|
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);
|
int hashCode_GC(struct hashmap_GC *t, uint64_t hash);
|
||||||
|
|
||||||
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash);
|
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash);
|
||||||
|
|
||||||
void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
|
void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
|
||||||
void *val, size_t order);
|
void *val, size_t order);
|
||||||
|
|
||||||
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash);
|
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash);
|
||||||
|
|
||||||
|
|||||||
253
src/runtime/objects/dictionary/dictionary.c
Normal file
253
src/runtime/objects/dictionary/dictionary.c
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
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 < 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);
|
||||||
|
|
||||||
|
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 != nodes_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___getattr__(size_t argc,
|
||||||
|
ArgonObject **argv,
|
||||||
|
ArErr *err,
|
||||||
|
RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 2) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__getattr__ 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___setattr__(size_t argc,
|
||||||
|
ArgonObject **argv,
|
||||||
|
ArErr *err,
|
||||||
|
RuntimeState *state) {
|
||||||
|
(void)state;
|
||||||
|
if (argc != 3) {
|
||||||
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
|
"__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];
|
||||||
|
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, __getattr__,
|
||||||
|
create_argon_native_function("__getattr__",
|
||||||
|
create_ARGON_DICTIONARY_TYPE___getattr__));
|
||||||
|
add_builtin_field(
|
||||||
|
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__));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *create_dictionary(struct hashmap_GC *hashmap) {
|
||||||
|
ArgonObject *object = new_instance(ARGON_DICTIONARY_TYPE);
|
||||||
|
object->type = TYPE_DICTIONARY;
|
||||||
|
object->value.as_hashmap = hashmap;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
17
src/runtime/objects/dictionary/dictionary.h
Normal file
17
src/runtime/objects/dictionary/dictionary.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DICTIONARY_H
|
||||||
|
#define DICTIONARY_H
|
||||||
|
#include "../object.h"
|
||||||
|
|
||||||
|
extern ArgonObject *ARGON_DICTIONARY_TYPE;
|
||||||
|
|
||||||
|
void create_ARGON_DICTIONARY_TYPE();
|
||||||
|
|
||||||
|
ArgonObject* create_dictionary(struct hashmap_GC*hashmap);
|
||||||
|
|
||||||
|
#endif // DICTIONARY_H
|
||||||
@@ -7,44 +7,48 @@
|
|||||||
#include "../../runtime.h"
|
#include "../../runtime.h"
|
||||||
#include "../object.h"
|
#include "../object.h"
|
||||||
#include "../string/string.h"
|
#include "../string/string.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
ArgonObject *ARGON_FUNCTION_TYPE = NULL;
|
ArgonObject *ARGON_FUNCTION_TYPE = NULL;
|
||||||
|
|
||||||
ArgonObject *create_argon_native_function(char*name, native_fn native_fn) {
|
ArgonObject *create_argon_native_function(char *name, native_fn native_fn) {
|
||||||
ArgonObject *object = new_object();
|
ArgonObject *object = new_instance(ARGON_FUNCTION_TYPE);
|
||||||
add_field(object, "__class__", ARGON_FUNCTION_TYPE);
|
|
||||||
object->type = TYPE_NATIVE_FUNCTION;
|
object->type = TYPE_NATIVE_FUNCTION;
|
||||||
add_field(object, "__name__", new_string_object(name, strlen(name)));
|
add_builtin_field(object, __name__,
|
||||||
|
new_string_object(name, strlen(name), 0, 0));
|
||||||
object->value.native_fn = native_fn;
|
object->value.native_fn = native_fn;
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_argon_function(Translated *translated, RuntimeState *state,
|
void load_argon_function(Translated *translated, RuntimeState *state,
|
||||||
struct Stack *stack) {
|
struct Stack *stack) {
|
||||||
ArgonObject *object = new_object();
|
ArgonObject *object = new_instance(ARGON_FUNCTION_TYPE);
|
||||||
add_field(object, "__class__", ARGON_FUNCTION_TYPE);
|
|
||||||
object->type = TYPE_FUNCTION;
|
object->type = TYPE_FUNCTION;
|
||||||
uint64_t offset = pop_bytecode(translated, state);
|
uint64_t offset = pop_bytecode(translated, state);
|
||||||
uint64_t length = pop_bytecode(translated, state);
|
uint64_t length = pop_bytecode(translated, state);
|
||||||
add_field(object, "__name__", new_string_object(arena_get(&translated->constants, offset), length));
|
add_builtin_field(object, __name__,
|
||||||
object->value.argon_fn.translated = *translated;
|
new_string_object(arena_get(&translated->constants, offset),
|
||||||
object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state);
|
length, 0, 0));
|
||||||
object->value.argon_fn.parameters =
|
uint64_t number_of_parameters = pop_bytecode(translated, state);
|
||||||
ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(struct string_struct));
|
object->value.argon_fn = ar_alloc(sizeof(struct argon_function_struct)+number_of_parameters *
|
||||||
for (size_t i = 0; i < object->value.argon_fn.number_of_parameters; i++) {
|
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);
|
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;
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE;
|
ArgonObject *ARGON_NUMBER_TYPE;
|
||||||
|
|
||||||
@@ -36,8 +37,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 +46,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 +73,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,95 +85,309 @@ ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
|||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_builtin_field(argv[1], __class__), __name__, argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__add__ cannot perform addition between a number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__add__ cannot perform addition between a number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_t r;
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
mpq_init(r);
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
mpq_add(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
ArgonObject *result = new_number_object(r);
|
bool gonna_overflow = (a > 0 && b > 0 && a > INT64_MAX - b) ||
|
||||||
mpq_clear(r);
|
(a < 0 && b < 0 && a < INT64_MIN - b);
|
||||||
return result;
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_int64(a + b);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number->is_int64 &&
|
||||||
|
!argv[1]->value.as_number->is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_add(r, *argv[0]->value.as_number->n.mpq,
|
||||||
|
*argv[1]->value.as_number->n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number->n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number->n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number->n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number->n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
"__subtract__ expects 2 arguments, got %" PRIu64, argc);
|
"__subtract__ expects 2 arguments, got %" PRIu64, argc);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_t r;
|
|
||||||
mpq_init(r);
|
|
||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_builtin_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_builtin_field(argv[1], __class__), __name__, argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__subtract__ cannot perform subtraction between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__subtract__ cannot perform subtraction between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_sub(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
|
||||||
ArgonObject *result = new_number_object(r);
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
mpq_clear(r);
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
return result;
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
|
int64_t neg_a = -a;
|
||||||
|
bool gonna_overflow = (neg_a > 0 && b > 0 && b > INT64_MAX - neg_a) ||
|
||||||
|
(neg_a < 0 && b < 0 && b < INT64_MIN - neg_a);
|
||||||
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_int64(a - b);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number->is_int64 &&
|
||||||
|
!argv[1]->value.as_number->is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_sub(r, *argv[0]->value.as_number->n.mpq,
|
||||||
|
*argv[1]->value.as_number->n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number->is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number->n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number->n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number->n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number->n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
"__multiply__ expects 2 arguments, got %" PRIu64, argc);
|
"__multiply__ 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(
|
||||||
"__multiply__ cannot perform multiplication between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__multiply__ cannot perform multiplication between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_mul(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
|
||||||
ArgonObject *result = new_number_object(r);
|
if (argv[0]->value.as_number->is_int64 && argv[1]->value.as_number->is_int64) {
|
||||||
mpq_clear(r);
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
return result;
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
"__division__ expects 2 arguments, got %" PRIu64, argc);
|
"__division__ 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(
|
||||||
"__division__ cannot perform division between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__division__ cannot perform division between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str->length, type_name->value.as_str->data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_div(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) {
|
||||||
ArgonObject *result = new_number_object(r);
|
int64_t a = argv[0]->value.as_number->n.i64;
|
||||||
mpq_clear(r);
|
int64_t b = argv[1]->value.as_number->n.i64;
|
||||||
return result;
|
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,
|
||||||
@@ -185,7 +399,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) {
|
||||||
@@ -327,39 +547,62 @@ 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].dict = NULL;
|
||||||
|
small_ints[i].value.as_number = &small_ints_as_number[i];
|
||||||
|
add_builtin_field(&small_ints[i], __class__, ARGON_NUMBER_TYPE);
|
||||||
|
small_ints[i].value.as_number->is_int64 = true;
|
||||||
|
small_ints[i].value.as_number->n.i64 = n;
|
||||||
|
small_ints[i].as_bool = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void create_ARGON_NUMBER_TYPE() {
|
void create_ARGON_NUMBER_TYPE() {
|
||||||
ARGON_NUMBER_TYPE = new_object();
|
ARGON_NUMBER_TYPE = new_class();
|
||||||
add_field(ARGON_NUMBER_TYPE, "__name__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __name__,
|
||||||
new_string_object_null_terminated("number"));
|
new_string_object_null_terminated("number"));
|
||||||
add_field(
|
add_builtin_field(
|
||||||
ARGON_NUMBER_TYPE, "__string__",
|
ARGON_NUMBER_TYPE, __string__,
|
||||||
create_argon_native_function("__string__", ARGON_NUMBER_TYPE___string__));
|
create_argon_native_function("__string__", ARGON_NUMBER_TYPE___string__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__new__",
|
add_builtin_field(
|
||||||
create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__));
|
ARGON_NUMBER_TYPE, __new__,
|
||||||
add_field(
|
create_argon_native_function("__new__", ARGON_NUMBER_TYPE___new__));
|
||||||
ARGON_NUMBER_TYPE, "__number__",
|
add_builtin_field(
|
||||||
|
ARGON_NUMBER_TYPE, __number__,
|
||||||
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
|
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__boolean__",
|
add_builtin_field(
|
||||||
create_argon_native_function("__boolean__",
|
ARGON_NUMBER_TYPE, __hash__,
|
||||||
ARGON_NUMBER_TYPE___boolean__));
|
create_argon_native_function("__hash__", ARGON_NUMBER_TYPE___hash__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__add__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __boolean__,
|
||||||
create_argon_native_function("__add__",
|
create_argon_native_function(
|
||||||
ARGON_NUMBER_TYPE___add__));
|
"__boolean__", ARGON_NUMBER_TYPE___boolean__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__subtract__",
|
add_builtin_field(
|
||||||
create_argon_native_function("__subtract__",
|
ARGON_NUMBER_TYPE, __add__,
|
||||||
ARGON_NUMBER_TYPE___subtract__));
|
create_argon_native_function("__add__", ARGON_NUMBER_TYPE___add__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__multiply__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __subtract__,
|
||||||
create_argon_native_function("__multiply__",
|
create_argon_native_function(
|
||||||
ARGON_NUMBER_TYPE___multiply__));
|
"__subtract__", ARGON_NUMBER_TYPE___subtract__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__division__",
|
add_builtin_field(ARGON_NUMBER_TYPE, __multiply__,
|
||||||
create_argon_native_function("__division__",
|
create_argon_native_function(
|
||||||
ARGON_NUMBER_TYPE___division__));
|
"__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) {
|
||||||
@@ -393,40 +636,129 @@ mpq_t *mpq_new_gc_from(const mpq_t src) {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mpq_to_int64(mpq_t q, int64_t *out) {
|
||||||
|
// Check denominator == 1
|
||||||
|
if (mpz_cmp_ui(mpq_denref(q), 1) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get numerator
|
||||||
|
mpz_t num;
|
||||||
|
mpz_init(num);
|
||||||
|
mpz_set(num, mpq_numref(q));
|
||||||
|
|
||||||
|
// Check bounds
|
||||||
|
if (mpz_cmp_si(num, INT64_MIN) < 0 || mpz_cmp_si(num, INT64_MAX) > 0) {
|
||||||
|
mpz_clear(num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = mpz_get_si(num); // safe because we checked range
|
||||||
|
mpz_clear(num);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool double_to_int64(double x, int64_t *out) {
|
||||||
|
if (x < (double)INT64_MIN || x > (double)INT64_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t i = (int64_t)x;
|
||||||
|
if ((double)i == x) { // no fractional part
|
||||||
|
*out = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object(mpq_t number) {
|
ArgonObject *new_number_object(mpq_t number) {
|
||||||
ArgonObject *object = new_object();
|
int64_t i64 = 0;
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
bool is_int64 = mpq_to_int64(number, &i64);
|
||||||
|
if (is_int64 && i64 >= small_ints_min && i64 <= small_ints_max) {
|
||||||
|
return &small_ints[i64 - small_ints_min];
|
||||||
|
}
|
||||||
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(number);
|
object->value.as_number->n.i64 = i64;
|
||||||
|
object->value.as_number->is_int64 = is_int64;
|
||||||
|
if (object->value.as_number->is_int64) {
|
||||||
|
object->as_bool = object->value.as_number->n.i64;
|
||||||
|
} else {
|
||||||
|
object->value.as_number->n.mpq = mpq_new_gc_from(number);
|
||||||
|
object->as_bool = mpq_cmp_si(number, 0, 1) != 0;
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_long(long n, unsigned long d) {
|
ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d) {
|
||||||
ArgonObject *object = new_object();
|
if (d == 1 && n >= small_ints_min && n <= small_ints_max) {
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
return &small_ints[n - small_ints_min];
|
||||||
mpq_t r;
|
}
|
||||||
mpq_init(r);
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
mpq_set_si(r, n, d);
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(r);
|
if (d == 1) {
|
||||||
mpq_clear(r);
|
object->value.as_number->is_int64 = true;
|
||||||
|
object->value.as_number->n.i64 = n;
|
||||||
|
object->as_bool = n;
|
||||||
|
} else {
|
||||||
|
object->value.as_number->is_int64 = false;
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_set_si(r, n, d);
|
||||||
|
object->value.as_number->n.mpq = mpq_new_gc_from(r);
|
||||||
|
object->as_bool = n != 0;
|
||||||
|
mpq_clear(r);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_number_object_from_int64(int64_t i64) {
|
||||||
|
if (i64 >= small_ints_min && i64 <= small_ints_max) {
|
||||||
|
return &small_ints[i64 - small_ints_min];
|
||||||
|
}
|
||||||
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
|
object->type = TYPE_NUMBER;
|
||||||
|
object->value.as_number->is_int64 = true;
|
||||||
|
object->value.as_number->n.i64 = i64;
|
||||||
|
object->as_bool = i64;
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_double(double d) {
|
ArgonObject *new_number_object_from_double(double d) {
|
||||||
ArgonObject *object = new_object();
|
int64_t i64 = 0;
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
bool is_int64 = double_to_int64(d, &i64);
|
||||||
mpq_t r;
|
if (is_int64 && i64 >= small_ints_min && i64 <= small_ints_max) {
|
||||||
mpq_init(r);
|
return &small_ints[i64 - small_ints_min];
|
||||||
mpq_set_d(r, d);
|
}
|
||||||
|
ArgonObject *object = new_instance(ARGON_NUMBER_TYPE);
|
||||||
|
object->value.as_number = ar_alloc(sizeof(struct as_number));
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(r);
|
object->value.as_number->n.i64 = i64;
|
||||||
mpq_clear(r);
|
object->value.as_number->is_int64 = is_int64;
|
||||||
|
if (object->value.as_number->is_int64) {
|
||||||
|
object->as_bool = object->value.as_number->n.i64;
|
||||||
|
} else {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_set_d(r, d);
|
||||||
|
object->value.as_number->n.mpq = mpq_new_gc_from(r);
|
||||||
|
object->as_bool = d != 0;
|
||||||
|
mpq_clear(r);
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_number(Translated *translated, RuntimeState *state) {
|
void load_number(Translated *translated, RuntimeState *state) {
|
||||||
uint8_t to_register = pop_byte(translated, state);
|
uint8_t to_register = pop_byte(translated, state);
|
||||||
|
uint8_t is_int64 = pop_byte(translated, state);
|
||||||
|
if (is_int64) {
|
||||||
|
state->registers[to_register] =
|
||||||
|
new_number_object_from_int64(pop_bytecode(translated, state));
|
||||||
|
return;
|
||||||
|
}
|
||||||
size_t num_size = pop_bytecode(translated, state);
|
size_t num_size = pop_bytecode(translated, state);
|
||||||
size_t num_pos = pop_bytecode(translated, state);
|
size_t num_pos = pop_bytecode(translated, state);
|
||||||
mpq_t r;
|
mpq_t r;
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ void create_ARGON_NUMBER_TYPE();
|
|||||||
|
|
||||||
ArgonObject *new_number_object(mpq_t number);
|
ArgonObject *new_number_object(mpq_t number);
|
||||||
|
|
||||||
|
bool mpq_to_int64(mpq_t q, int64_t *out);
|
||||||
|
|
||||||
void load_number(Translated *translated, RuntimeState *state);
|
void load_number(Translated *translated, RuntimeState *state);
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_double(double d);
|
ArgonObject *new_number_object_from_double(double d);
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_long(long n, unsigned long d);
|
ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d);
|
||||||
|
|
||||||
|
ArgonObject *new_number_object_from_int64(int64_t i64);
|
||||||
|
|
||||||
#endif // RUNTIME_NUMBER_H
|
#endif // RUNTIME_NUMBER_H
|
||||||
@@ -7,48 +7,159 @@
|
|||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "../../hash_data/hash_data.h"
|
#include "../../hash_data/hash_data.h"
|
||||||
#include "../../memory.h"
|
#include "../../memory.h"
|
||||||
|
#include "../call/call.h"
|
||||||
#include "type/type.h"
|
#include "type/type.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
int strcmp_len(const char *s1, size_t len, const char *s2) {
|
||||||
|
size_t s2len = strlen(s2); // length of null-terminated string
|
||||||
|
size_t n = (len < s2len) ? len : s2len;
|
||||||
|
|
||||||
|
int cmp = memcmp(s1, s2, n);
|
||||||
|
if (cmp != 0)
|
||||||
|
return cmp;
|
||||||
|
|
||||||
|
// If prefixes match, decide based on length
|
||||||
|
if (len == s2len)
|
||||||
|
return 0;
|
||||||
|
return (len < s2len) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
ArgonObject *BASE_CLASS = NULL;
|
ArgonObject *BASE_CLASS = NULL;
|
||||||
|
|
||||||
|
const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
||||||
|
"__base__",
|
||||||
|
"__class__",
|
||||||
|
"__name__",
|
||||||
|
"", // above is anything that gets stored in built in slots
|
||||||
|
"__binding__",
|
||||||
|
"__function__",
|
||||||
|
"__add__",
|
||||||
|
"__string__",
|
||||||
|
"__subtract__",
|
||||||
|
"__multiply__",
|
||||||
|
"__divide__",
|
||||||
|
"__new__",
|
||||||
|
"__init__",
|
||||||
|
"__boolean__",
|
||||||
|
"__getattr__",
|
||||||
|
"__getitem__",
|
||||||
|
"address",
|
||||||
|
"__call__",
|
||||||
|
"__number__",
|
||||||
|
"length",
|
||||||
|
"__getattribute__",
|
||||||
|
"__setattr__",
|
||||||
|
"__setitem__",
|
||||||
|
"__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) {
|
||||||
|
return (int64_t)object;
|
||||||
|
}
|
||||||
|
ArgonObject *hash_result = argon_call(hash_function, 0, NULL, err, state);
|
||||||
|
if (hash_result->type != TYPE_NUMBER ||
|
||||||
|
!hash_result->value.as_number->is_int64) {
|
||||||
|
*err =
|
||||||
|
create_err(err->line, err->column, err->length, err->path, "Hash Error",
|
||||||
|
"hash result needs to be a 64 bit integer.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return hash_result->value.as_number->n.i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_class() {
|
||||||
|
ArgonObject *object = new_object();
|
||||||
|
add_builtin_field(object, __class__, ARGON_TYPE_TYPE);
|
||||||
|
add_builtin_field(object, __base__, BASE_CLASS);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *new_instance(ArgonObject *of) {
|
||||||
|
ArgonObject *object = new_object();
|
||||||
|
add_builtin_field(object, __class__, of);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_builtin_field(ArgonObject *target, built_in_fields field,
|
||||||
|
ArgonObject *object) {
|
||||||
|
for (size_t i = 0; i < target->built_in_slot_length; i++) {
|
||||||
|
if (target->built_in_slot[i].field == field) {
|
||||||
|
target->built_in_slot[i].value = object;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field > BUILT_IN_ARRAY_COUNT) {
|
||||||
|
if (!target->dict)
|
||||||
|
target->dict = createHashmap_GC();
|
||||||
|
hashmap_insert_GC(target->dict, built_in_field_hashes[field],
|
||||||
|
(char *)built_in_field_names[field], object, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target->built_in_slot[target->built_in_slot_length++] =
|
||||||
|
(struct built_in_slot){field, object};
|
||||||
|
// hashmap_insert_GC(target->dict, built_in_field_hashes[field],
|
||||||
|
// (char *)built_in_field_names[field], object, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_field_l(ArgonObject *target, char *name, uint64_t hash, size_t length,
|
||||||
|
ArgonObject *object) {
|
||||||
|
for (size_t i = 0; i < BUILT_IN_ARRAY_COUNT; i++) {
|
||||||
|
if (strcmp_len(name, length, built_in_field_names[i]) == 0) {
|
||||||
|
add_builtin_field(target, i, object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target->dict)
|
||||||
|
target->dict = createHashmap_GC();
|
||||||
|
char *name_copy = ar_alloc(length);
|
||||||
|
memcpy(name_copy, name, length);
|
||||||
|
name_copy[length] = '\0';
|
||||||
|
hashmap_insert_GC(target->dict, hash, name_copy, object, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *bind_object_to_function(ArgonObject *object,
|
ArgonObject *bind_object_to_function(ArgonObject *object,
|
||||||
ArgonObject *function) {
|
ArgonObject *function) {
|
||||||
ArgonObject *bound_method_wrapper = new_object();
|
ArgonObject *bound_method_wrapper = new_object();
|
||||||
bound_method_wrapper->type = TYPE_METHOD;
|
bound_method_wrapper->type = TYPE_METHOD;
|
||||||
add_field(bound_method_wrapper, "__class__", ARGON_METHOD_TYPE);
|
add_builtin_field(bound_method_wrapper, __class__, ARGON_METHOD_TYPE);
|
||||||
add_field(bound_method_wrapper, "__binding__", object);
|
add_builtin_field(bound_method_wrapper, __binding__, object);
|
||||||
add_field(bound_method_wrapper, "__function__", function);
|
add_builtin_field(bound_method_wrapper, __function__, function);
|
||||||
ArgonObject *function_name = get_field(function, "__name__", false, false);
|
ArgonObject *function_name = get_builtin_field(function, __name__);
|
||||||
if (function_name)
|
if (function_name)
|
||||||
add_field(bound_method_wrapper, "__name__", function_name);
|
add_builtin_field(bound_method_wrapper, __name__, function_name);
|
||||||
return bound_method_wrapper;
|
return bound_method_wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
||||||
size_t length, ArgonObject *binding_object) {
|
uint64_t hash, size_t length,
|
||||||
char *field = "__base__";
|
ArgonObject *binding_object) {
|
||||||
size_t field_size = strlen(field);
|
|
||||||
while (target) {
|
while (target) {
|
||||||
ArgonObject *object = get_field_l(target, name, length, false, false);
|
ArgonObject *object = get_field_l(target, name, hash, length, false, false);
|
||||||
if (object) {
|
if (object) {
|
||||||
if ((object->type == TYPE_FUNCTION ||
|
if ((object->type == TYPE_FUNCTION ||
|
||||||
object->type == TYPE_NATIVE_FUNCTION) &&
|
object->type == TYPE_NATIVE_FUNCTION) &&
|
||||||
@@ -57,35 +168,74 @@ ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
|||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
target = get_field_l(target, field, field_size, false, false);
|
target = get_builtin_field(target, __base__);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *get_field_l(ArgonObject *target, char *name, size_t length,
|
ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash,
|
||||||
bool recursive, bool disable_method_wrapper) {
|
size_t length, bool recursive,
|
||||||
if(!target|| !target->dict) return NULL;
|
bool disable_method_wrapper) {
|
||||||
char *field = "__class__";
|
for (size_t i = 0; i < target->built_in_slot_length; i++) {
|
||||||
size_t field_size = strlen(field);
|
if (strcmp_len(name, length, built_in_field_names[i]) == 0) {
|
||||||
ArgonObject *object = hashmap_lookup_GC(
|
return target->built_in_slot[i].value;
|
||||||
target->dict, siphash64_bytes(name, length, siphash_key));
|
}
|
||||||
|
}
|
||||||
|
if (!target->dict)
|
||||||
|
return NULL;
|
||||||
|
ArgonObject *object = hashmap_lookup_GC(target->dict, hash);
|
||||||
if (!recursive || object)
|
if (!recursive || object)
|
||||||
return object;
|
return object;
|
||||||
ArgonObject *binding = target;
|
ArgonObject *binding = target;
|
||||||
if (disable_method_wrapper)
|
if (disable_method_wrapper)
|
||||||
binding = NULL;
|
binding = NULL;
|
||||||
return get_field_for_class_l(
|
return get_field_for_class_l(get_builtin_field(target, __class__), name, hash,
|
||||||
hashmap_lookup_GC(target->dict,
|
length, binding);
|
||||||
siphash64_bytes(field, field_size, siphash_key)),
|
|
||||||
name, length, binding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive,
|
ArgonObject *get_builtin_field_for_class(ArgonObject *target,
|
||||||
bool disable_method_wrapper) {
|
built_in_fields field,
|
||||||
return get_field_l(target, name, strlen(name), recursive,
|
ArgonObject *binding_object) {
|
||||||
disable_method_wrapper);
|
while (target) {
|
||||||
|
ArgonObject *object = get_builtin_field(target, field);
|
||||||
|
if (object) {
|
||||||
|
if ((object->type == TYPE_FUNCTION ||
|
||||||
|
object->type == TYPE_NATIVE_FUNCTION) &&
|
||||||
|
binding_object) {
|
||||||
|
object = bind_object_to_function(binding_object, object);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
target = get_builtin_field(target, __base__);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
|
inline ArgonObject *get_builtin_field(ArgonObject *target,
|
||||||
ArgonObject *binding_object) {
|
built_in_fields field) {
|
||||||
return get_field_for_class_l(target, name, strlen(name), binding_object);
|
return get_builtin_field_with_recursion_support(target, field, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgonObject *
|
||||||
|
get_builtin_field_with_recursion_support(ArgonObject *target,
|
||||||
|
built_in_fields field, bool recursive,
|
||||||
|
bool disable_method_wrapper) {
|
||||||
|
if (!target)
|
||||||
|
return NULL;
|
||||||
|
for (size_t i = 0; i < target->built_in_slot_length; i++) {
|
||||||
|
if (target->built_in_slot[i].field == field) {
|
||||||
|
return target->built_in_slot[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target->dict)
|
||||||
|
return NULL;
|
||||||
|
ArgonObject *object =
|
||||||
|
hashmap_lookup_GC(target->dict, built_in_field_hashes[field]);
|
||||||
|
if (!recursive || object)
|
||||||
|
return object;
|
||||||
|
ArgonObject *binding = target;
|
||||||
|
if (disable_method_wrapper)
|
||||||
|
binding = NULL;
|
||||||
|
return get_builtin_field_for_class(
|
||||||
|
hashmap_lookup_GC(target->dict, built_in_field_hashes[__class__]), field,
|
||||||
|
binding);
|
||||||
}
|
}
|
||||||
@@ -9,27 +9,44 @@
|
|||||||
#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;
|
extern const char *built_in_field_names[BUILT_IN_FIELDS_COUNT];
|
||||||
ArgonObject *new_object();
|
|
||||||
|
|
||||||
void add_field(ArgonObject *target, char *name, ArgonObject *object);
|
typedef struct ArgonObject ArgonObject;
|
||||||
|
|
||||||
|
ArgonObject *new_class();
|
||||||
|
ArgonObject *new_instance(ArgonObject * of);
|
||||||
|
|
||||||
|
void init_built_in_field_hashes();
|
||||||
|
|
||||||
|
int64_t hash_object(ArgonObject *object, ArErr *err, RuntimeState *state);
|
||||||
|
|
||||||
|
void add_builtin_field(ArgonObject *target, built_in_fields field,
|
||||||
|
ArgonObject *object);
|
||||||
|
|
||||||
|
void add_field_l(ArgonObject *target, char *name, uint64_t hash, size_t length,
|
||||||
|
ArgonObject *object);
|
||||||
|
|
||||||
ArgonObject *bind_object_to_function(ArgonObject *object,
|
ArgonObject *bind_object_to_function(ArgonObject *object,
|
||||||
ArgonObject *function);
|
ArgonObject *function);
|
||||||
|
|
||||||
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
ArgonObject *get_field_for_class_l(ArgonObject *target, char *name,
|
||||||
size_t length, ArgonObject *binding_object);
|
uint64_t hash, size_t length,
|
||||||
|
ArgonObject *binding_object);
|
||||||
|
|
||||||
ArgonObject *get_field_l(ArgonObject *target, char *name, size_t length,
|
ArgonObject *get_field_l(ArgonObject *target, char *name, uint64_t hash,
|
||||||
bool recursive, bool disable_method_wrapper);
|
size_t length, bool recursive,
|
||||||
|
bool disable_method_wrapper);
|
||||||
|
|
||||||
ArgonObject *get_field_for_class(ArgonObject *target, char *name,
|
ArgonObject *get_builtin_field_for_class(ArgonObject *target,
|
||||||
ArgonObject *binding_object);
|
built_in_fields field,
|
||||||
|
ArgonObject *binding_object);
|
||||||
|
|
||||||
ArgonObject *get_field(ArgonObject *target, char *name, bool recursive,
|
ArgonObject *get_builtin_field(ArgonObject *target, built_in_fields field);
|
||||||
bool disable_method_wrapper);
|
|
||||||
|
ArgonObject *get_builtin_field_with_recursion_support(ArgonObject *target, built_in_fields field, bool recursive, bool disable_method_wrapper);
|
||||||
|
|
||||||
#endif // OBJECT_H
|
#endif // OBJECT_H
|
||||||
@@ -4,27 +4,115 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "../../call/call.h"
|
||||||
|
#include "../number/number.h"
|
||||||
#include "../object.h"
|
#include "../object.h"
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "string.h"
|
|
||||||
#include "../number/number.h"
|
|
||||||
|
|
||||||
ArgonObject *ARGON_STRING_TYPE = NULL;
|
ArgonObject *ARGON_STRING_TYPE = NULL;
|
||||||
|
|
||||||
ArgonObject *new_string_object(char*data, size_t length) {
|
char *c_quote_string(const char *input, size_t len) {
|
||||||
ArgonObject * object = new_object();
|
// Worst case: every byte becomes "\uXXXX" (6 chars) + quotes + NUL
|
||||||
add_field(object, "__class__", ARGON_STRING_TYPE);
|
size_t max_out = 2 + (len * 6) + 1;
|
||||||
add_field(object, "length", new_number_object_from_long(length, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return new_string_object(data, strlen(data), 0, 0);
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,19 @@
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
ArgonObject *new_string_object_null_terminated(char*data);
|
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_null_terminated(char *data);
|
||||||
#endif // STRING_OBJ_H
|
#endif // STRING_OBJ_H
|
||||||
@@ -13,14 +13,14 @@ ArgonObject *term_log(size_t argc, ArgonObject **argv, ArErr *err,
|
|||||||
for (size_t i = 0; i < argc; i++) {
|
for (size_t i = 0; i < argc; i++) {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
ArgonObject *string_convert_method = get_field_for_class(
|
ArgonObject *string_convert_method = get_builtin_field_for_class(
|
||||||
get_field(argv[i], "__class__", false, false), "__string__", argv[i]);
|
get_builtin_field(argv[i], __class__), __string__, argv[i]);
|
||||||
|
|
||||||
if (string_convert_method) {
|
if (string_convert_method) {
|
||||||
ArgonObject *string_object =
|
ArgonObject *string_object =
|
||||||
argon_call(string_convert_method, 0, NULL, err, state);
|
argon_call(string_convert_method, 0, NULL, err, state);
|
||||||
fwrite(string_object->value.as_str.data, sizeof(char),
|
fwrite(string_object->value.as_str->data, sizeof(char),
|
||||||
string_object->value.as_str.length, stdout);
|
string_object->value.as_str->length, stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,12 @@
|
|||||||
#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)
|
||||||
|
|
||||||
|
#define MAX_REGISTERS 256
|
||||||
|
|
||||||
extern ArgonObject *ARGON_METHOD_TYPE;
|
extern ArgonObject *ARGON_METHOD_TYPE;
|
||||||
extern Stack *Global_Scope;
|
extern Stack *Global_Scope;
|
||||||
@@ -54,8 +60,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 +68,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
|
||||||
75
src/shell.c
75
src/shell.c
@@ -9,6 +9,10 @@
|
|||||||
#include "./runtime/objects/term/term.h"
|
#include "./runtime/objects/term/term.h"
|
||||||
#include "./runtime/runtime.h"
|
#include "./runtime/runtime.h"
|
||||||
#include "./translator/translator.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 <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -19,6 +23,7 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
||||||
if (strchr(mode, 'r') == NULL) {
|
if (strchr(mode, 'r') == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -37,6 +42,46 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
|||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only define ssize_t if it doesn't already exist
|
||||||
|
#ifndef _SSIZE_T_DEFINED
|
||||||
|
typedef long ssize_t;
|
||||||
|
#define _SSIZE_T_DEFINED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||||
|
if (!lineptr || !n || !stream)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (*lineptr == NULL || *n == 0) {
|
||||||
|
*n = 128;
|
||||||
|
*lineptr = malloc(*n);
|
||||||
|
if (!*lineptr)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = fgetc(stream)) != EOF) {
|
||||||
|
if (pos + 1 >= *n) {
|
||||||
|
*n *= 2;
|
||||||
|
char *tmp = realloc(*lineptr, *n);
|
||||||
|
if (!tmp)
|
||||||
|
return -1;
|
||||||
|
*lineptr = tmp;
|
||||||
|
}
|
||||||
|
(*lineptr)[pos++] = c;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == 0 && c == EOF)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
(*lineptr)[pos] = '\0';
|
||||||
|
return (ssize_t)pos;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#include "../external/linenoise/linenoise.h"
|
#include "../external/linenoise/linenoise.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -55,7 +100,7 @@ int execute_code(FILE *stream, char *path, Stack *scope,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArErr err;
|
ArErr err = no_err;
|
||||||
|
|
||||||
DArray tokens;
|
DArray tokens;
|
||||||
darray_init(&tokens, sizeof(Token));
|
darray_init(&tokens, sizeof(Token));
|
||||||
@@ -91,7 +136,8 @@ int execute_code(FILE *stream, char *path, Stack *scope,
|
|||||||
|
|
||||||
hashmap_free(__translated.constants.hashmap, NULL);
|
hashmap_free(__translated.constants.hashmap, NULL);
|
||||||
Translated translated = {
|
Translated translated = {
|
||||||
__translated.registerCount, NULL, {}, {}, __translated.path};
|
__translated.registerCount, __translated.registerAssignment, NULL, {}, {},
|
||||||
|
__translated.path};
|
||||||
translated.bytecode.data = ar_alloc(__translated.bytecode.capacity);
|
translated.bytecode.data = ar_alloc(__translated.bytecode.capacity);
|
||||||
memcpy(translated.bytecode.data, __translated.bytecode.data,
|
memcpy(translated.bytecode.data, __translated.bytecode.data,
|
||||||
__translated.bytecode.capacity);
|
__translated.bytecode.capacity);
|
||||||
@@ -108,7 +154,7 @@ int execute_code(FILE *stream, char *path, Stack *scope,
|
|||||||
darray_free(&__translated.bytecode, NULL);
|
darray_free(&__translated.bytecode, NULL);
|
||||||
free(__translated.constants.data);
|
free(__translated.constants.data);
|
||||||
*runtime_state = init_runtime_state(translated, path);
|
*runtime_state = init_runtime_state(translated, path);
|
||||||
err = runtime(translated, *runtime_state, scope);
|
runtime(translated, *runtime_state, scope, &err);
|
||||||
if (err.exists) {
|
if (err.exists) {
|
||||||
output_err(err);
|
output_err(err);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -166,8 +212,7 @@ char *read_all_stdin(size_t *out_len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int shell() {
|
int shell() {
|
||||||
|
Stack *main_scope = create_scope(Global_Scope, true);
|
||||||
Stack *main_scope = create_scope(Global_Scope);
|
|
||||||
|
|
||||||
if (!isatty(STDIN_FILENO)) {
|
if (!isatty(STDIN_FILENO)) {
|
||||||
RuntimeState runtime_state;
|
RuntimeState runtime_state;
|
||||||
@@ -179,10 +224,14 @@ int shell() {
|
|||||||
free(data);
|
free(data);
|
||||||
return resp;
|
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);
|
signal(SIGINT, handle_sigint);
|
||||||
|
|
||||||
printf("Welcome to the Argon shell!\n\n");
|
printf("Argon (Chloride %s)\nType \"license\" for more information.\n",
|
||||||
|
version_string);
|
||||||
|
|
||||||
ArgonObject *output_object = create_argon_native_function("log", term_log);
|
ArgonObject *output_object = create_argon_native_function("log", term_log);
|
||||||
char *totranslate = NULL;
|
char *totranslate = NULL;
|
||||||
@@ -198,11 +247,13 @@ int shell() {
|
|||||||
totranslatelength = 0;
|
totranslatelength = 0;
|
||||||
};
|
};
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
|
int last_indent = 0;
|
||||||
char textBefore[] = ">>> ";
|
char textBefore[] = ">>> ";
|
||||||
|
|
||||||
// Dynamic array of lines
|
// Dynamic array of lines
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
last_indent = indent;
|
||||||
// indent string
|
// indent string
|
||||||
size_t isz = (size_t)indent * 4;
|
size_t isz = (size_t)indent * 4;
|
||||||
char *indentStr = (char *)malloc(isz + 1);
|
char *indentStr = (char *)malloc(isz + 1);
|
||||||
@@ -253,7 +304,7 @@ int shell() {
|
|||||||
strcpy(textBefore, "... ");
|
strcpy(textBefore, "... ");
|
||||||
free(indentStr);
|
free(indentStr);
|
||||||
|
|
||||||
} while (indent > 0);
|
} while (indent > 0 || last_indent != 0);
|
||||||
totranslate = realloc(totranslate, totranslatelength + 1);
|
totranslate = realloc(totranslate, totranslatelength + 1);
|
||||||
totranslate[totranslatelength] = '\0';
|
totranslate[totranslatelength] = '\0';
|
||||||
RuntimeState runtime_state;
|
RuntimeState runtime_state;
|
||||||
@@ -263,9 +314,13 @@ int shell() {
|
|||||||
if (resp) {
|
if (resp) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ArErr err;
|
if (runtime_state.registers[0] &&
|
||||||
argon_call(output_object, 1, (ArgonObject *[]){runtime_state.registers[0]},
|
runtime_state.registers[0] != ARGON_NULL) {
|
||||||
&err, &runtime_state);
|
ArErr err = no_err;
|
||||||
|
argon_call(output_object, 1,
|
||||||
|
(ArgonObject *[]){runtime_state.registers[0]}, &err,
|
||||||
|
&runtime_state);
|
||||||
|
}
|
||||||
totranslatelength = 0;
|
totranslatelength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,4 @@
|
|||||||
|
|
||||||
int shell();
|
int shell();
|
||||||
|
|
||||||
#endif // ARGON_SHELL_H
|
#endif // ARGON_SHELL_H
|
||||||
@@ -8,23 +8,18 @@
|
|||||||
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, access->access.size + 2);
|
push_instruction_code(translated, 1);
|
||||||
|
|
||||||
translate_parsed(translated, &access->to_access, err);
|
translate_parsed(translated, access->access, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||||
push_instruction_code(translated, 0);
|
push_instruction_code(translated, 0);
|
||||||
push_instruction_byte(translated, OP_LOAD_BOOL);
|
|
||||||
push_instruction_byte(translated, access->access_fields);
|
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
|
||||||
push_instruction_code(translated, 1);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < access->access.size; i++) {
|
|
||||||
translate_parsed(translated, darray_get(&access->access, i), err);
|
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
|
||||||
push_instruction_code(translated, 2+i);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
80
src/translator/assignment/assignment.c
Normal file
80
src/translator/assignment/assignment.c
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assignment.h"
|
||||||
|
#include "../../hash_data/hash_data.h"
|
||||||
|
#include "../../parser/assignable/access/access.h"
|
||||||
|
#include "../../parser/assignable/identifier/identifier.h"
|
||||||
|
#include "../translator.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
size_t translate_parsed_assignment(Translated *translated,
|
||||||
|
ParsedAssign *assignment, ArErr *err) {
|
||||||
|
set_registers(translated, 1);
|
||||||
|
DArray *old_return_jumps = translated->return_jumps;
|
||||||
|
translated->return_jumps = NULL;
|
||||||
|
size_t first = translate_parsed(translated, assignment->from, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
switch (assignment->to->type) {
|
||||||
|
case AST_IDENTIFIER:;
|
||||||
|
ParsedIdentifier *identifier = assignment->to->data;
|
||||||
|
size_t length = strlen(identifier->name);
|
||||||
|
size_t offset =
|
||||||
|
arena_push(&translated->constants, identifier->name, length);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
||||||
|
push_instruction_code(translated, identifier->line);
|
||||||
|
push_instruction_code(translated, identifier->column);
|
||||||
|
push_instruction_code(translated, length);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_ASSIGN);
|
||||||
|
push_instruction_code(translated, length);
|
||||||
|
push_instruction_code(translated, offset);
|
||||||
|
push_instruction_code(translated,
|
||||||
|
siphash64_bytes(identifier->name, length,
|
||||||
|
siphash_key_fixed_for_translator));
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
break;
|
||||||
|
case AST_ACCESS:;
|
||||||
|
ParsedAccess *access = assignment->to->data;
|
||||||
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
|
set_registers(translated, registerA);
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
translate_parsed(translated, access->to_access, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
push_instruction_byte(translated, OP_LOAD_SETATTR_METHOD);
|
||||||
|
push_instruction_byte(translated, OP_INIT_CALL);
|
||||||
|
push_instruction_code(translated, 2);
|
||||||
|
translate_parsed(translated, access->access, err);
|
||||||
|
if (err->exists)
|
||||||
|
return 0;
|
||||||
|
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||||
|
push_instruction_code(translated, 0);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||||
|
push_instruction_code(translated, 1);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_CALL);
|
||||||
|
translated->registerAssignment--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "panic: unsupported assignment\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
translated->return_jumps = old_return_jumps;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
15
src/translator/assignment/assignment.h
Normal file
15
src/translator/assignment/assignment.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BYTECODE_ASSIGNMENT_H
|
||||||
|
#define BYTECODE_ASSIGNMENT_H
|
||||||
|
#include "../translator.h"
|
||||||
|
#include "../../parser/assignable/assign/assign.h"
|
||||||
|
|
||||||
|
size_t translate_parsed_assignment(Translated *translated,
|
||||||
|
ParsedAssign *assignment, ArErr *err);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -29,6 +29,17 @@ this operation takes 3 operands.
|
|||||||
1. the fixed hash of the variable name.
|
1. the fixed hash of the variable name.
|
||||||
1. the register of the given value (*)
|
1. the register of the given value (*)
|
||||||
|
|
||||||
|
## OP_ASSIGN
|
||||||
|
|
||||||
|
assigns to a variable in the stack. if the variable doesnt exist on the stack, it is automatically declared on the current scope.
|
||||||
|
|
||||||
|
this operation takes 3 operands.
|
||||||
|
|
||||||
|
1. the length of the variable name.
|
||||||
|
1. the offset in the constant buffer of the variable name.
|
||||||
|
1. the fixed hash of the variable name.
|
||||||
|
1. the register of the given value (*)
|
||||||
|
|
||||||
## OP_LOAD_NULL
|
## OP_LOAD_NULL
|
||||||
|
|
||||||
sets a given register to null.
|
sets a given register to null.
|
||||||
@@ -60,9 +71,7 @@ initilises a function to a given register.
|
|||||||
|
|
||||||
## OP_BOOL
|
## OP_BOOL
|
||||||
|
|
||||||
converts a value in a given register into true or false depending on the result from \_\_bool\_\_
|
converts a value in register 0 into true or false depending on the result from \_\_bool\_\_ (using asBool if the object is a primitive)
|
||||||
|
|
||||||
1. the register to read and write to. (*)
|
|
||||||
|
|
||||||
## OP_JUMP_IF_FALSE
|
## OP_JUMP_IF_FALSE
|
||||||
|
|
||||||
@@ -71,17 +80,20 @@ jumps when a the value in the given register is false.
|
|||||||
1. the register to read. (*)
|
1. the register to read. (*)
|
||||||
1. the index to jump to.
|
1. the index to jump to.
|
||||||
|
|
||||||
## OP_JUMP_IF_FALSE
|
## OP_JUMP
|
||||||
|
|
||||||
jumps unconditionally to an index.
|
jumps unconditionally to an index.
|
||||||
|
|
||||||
1. the index to jump to.
|
1. the index to jump to.
|
||||||
|
|
||||||
|
|
||||||
## OP_NEW_SCOPE
|
## OP_NEW_SCOPE
|
||||||
|
|
||||||
creates a new stack
|
creates a new stack
|
||||||
|
|
||||||
|
## OP_EMPTY_SCOPE
|
||||||
|
|
||||||
|
empties the current scope so the same memory can be reused.
|
||||||
|
|
||||||
## OP_POP_SCOPE
|
## OP_POP_SCOPE
|
||||||
|
|
||||||
pops the top scope off the current
|
pops the top scope off the current
|
||||||
@@ -108,39 +120,83 @@ 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 0 and put it into register 0
|
||||||
|
|
||||||
## OP_LOAD_BOOL
|
## OP_LOAD_BOOL
|
||||||
|
|
||||||
loads a boolean into register 1
|
loads a boolean into register 0
|
||||||
|
|
||||||
1. byte representing true or false (1 or 0) *
|
1. byte representing true or false (1 or 0) *
|
||||||
|
|
||||||
## 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
|
||||||
|
|
||||||
## OP_LOAD_MULTIPLY_FUNCTION
|
performs an addition between register A and register B, storing the result in register C
|
||||||
|
|
||||||
loads the multiply function into register 1
|
1. the register A (*)
|
||||||
|
2. the register B (*)
|
||||||
|
2. the register C (*)
|
||||||
|
|
||||||
## OP_LOAD_DIVISION_FUNCTION
|
## OP_SUBTRACTION
|
||||||
|
|
||||||
loads the division function into register 1
|
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 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
|
||||||
@@ -14,17 +14,18 @@
|
|||||||
size_t translate_parsed_function(Translated *translated,
|
size_t translate_parsed_function(Translated *translated,
|
||||||
ParsedFunction *parsedFunction, ArErr *err) {
|
ParsedFunction *parsedFunction, ArErr *err) {
|
||||||
DArray main_bytecode = translated->bytecode;
|
DArray main_bytecode = translated->bytecode;
|
||||||
DArray _temp_bytecode;
|
uint8_t old_assignment = translated->registerAssignment;
|
||||||
darray_init(&_temp_bytecode, sizeof(uint8_t));
|
translated->registerAssignment = 1;
|
||||||
|
darray_init(&translated->bytecode, sizeof(uint8_t));
|
||||||
set_registers(translated, 1);
|
set_registers(translated, 1);
|
||||||
translated->bytecode = _temp_bytecode;
|
|
||||||
translate_parsed(translated, parsedFunction->body, err);
|
translate_parsed(translated, parsedFunction->body, err);
|
||||||
size_t function_bytecode_offset =
|
size_t function_bytecode_offset =
|
||||||
arena_push(&translated->constants, translated->bytecode.data,
|
arena_push(&translated->constants, translated->bytecode.data,
|
||||||
translated->bytecode.size*translated->bytecode.element_size);
|
translated->bytecode.size*translated->bytecode.element_size);
|
||||||
size_t function_bytecode_length = translated->bytecode.size;
|
size_t function_bytecode_length = translated->bytecode.size;
|
||||||
|
darray_free(&translated->bytecode, NULL);
|
||||||
translated->bytecode = main_bytecode;
|
translated->bytecode = main_bytecode;
|
||||||
darray_free(&_temp_bytecode, NULL);
|
translated->registerAssignment = old_assignment;
|
||||||
size_t start = push_instruction_byte(translated, OP_LOAD_FUNCTION);
|
size_t start = push_instruction_byte(translated, OP_LOAD_FUNCTION);
|
||||||
size_t offset = arena_push(&translated->constants, parsedFunction->name,
|
size_t offset = arena_push(&translated->constants, parsedFunction->name,
|
||||||
strlen(parsedFunction->name));
|
strlen(parsedFunction->name));
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ size_t translate_parsed_if(Translated *translated, DArray *parsedIf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
push_instruction_byte(translated, OP_BOOL);
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
push_instruction_byte(translated, 0);
|
|
||||||
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
||||||
push_instruction_byte(translated, 0);
|
push_instruction_byte(translated, 0);
|
||||||
uint64_t last_jump_index = push_instruction_code(translated, 0);
|
uint64_t last_jump_index = push_instruction_code(translated, 0);
|
||||||
|
|||||||
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
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "number.h"
|
#include "number.h"
|
||||||
|
#include "../../runtime/objects/number/number.h"
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -16,6 +17,13 @@ size_t translate_parsed_number(Translated *translated, mpq_t *number,
|
|||||||
set_registers(translated, to_register + 1);
|
set_registers(translated, to_register + 1);
|
||||||
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
|
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
|
||||||
push_instruction_byte(translated, to_register);
|
push_instruction_byte(translated, to_register);
|
||||||
|
int64_t i64;
|
||||||
|
uint8_t is_int64 = mpq_to_int64(*number, &i64);
|
||||||
|
push_instruction_byte(translated, is_int64);
|
||||||
|
if (is_int64) {
|
||||||
|
push_instruction_code(translated, i64);
|
||||||
|
return start;
|
||||||
|
}
|
||||||
size_t num_size;
|
size_t num_size;
|
||||||
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
|
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
|
||||||
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
|
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
|
||||||
|
|||||||
@@ -6,42 +6,94 @@
|
|||||||
|
|
||||||
#include "operation.h"
|
#include "operation.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
size_t translate_operation(Translated *translated, ParsedOperation *operation,
|
size_t translate_operation(Translated *translated, ParsedOperation *operation,
|
||||||
ArErr *err) {
|
ArErr *err) {
|
||||||
set_registers(translated, 1);
|
if (operation->operation == TOKEN_AND || operation->operation == TOKEN_OR) {
|
||||||
uint64_t first;
|
size_t *jump_to_if_false =
|
||||||
switch (operation->operation) {
|
checked_malloc(operation->to_operate_on.size * sizeof(size_t));
|
||||||
case TOKEN_PLUS:;
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
first = push_instruction_byte(translated, OP_LOAD_ADDITION_FUNCTION);
|
set_registers(translated, translated->registerAssignment);
|
||||||
break;
|
uint64_t first = 0;
|
||||||
case TOKEN_MINUS:
|
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
||||||
first = push_instruction_byte(translated, OP_LOAD_SUBTRACTION_FUNCTION);
|
uint64_t position = translate_parsed(
|
||||||
break;
|
translated, darray_get(&operation->to_operate_on, i), err);
|
||||||
case TOKEN_STAR:
|
if (i == 0)
|
||||||
first = push_instruction_byte(translated, OP_LOAD_MULTIPLY_FUNCTION);
|
first = position;
|
||||||
break;
|
if (err->exists) {
|
||||||
case TOKEN_SLASH:
|
free(jump_to_if_false);
|
||||||
first = push_instruction_byte(translated, OP_LOAD_DIVISION_FUNCTION);
|
return first;
|
||||||
break;
|
}
|
||||||
default:
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
*err = create_err(operation->line, operation->column, operation->length,
|
push_instruction_byte(translated, 0);
|
||||||
translated->path, "Syntax Error", "unknown operation");
|
push_instruction_byte(translated, registerA);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
push_instruction_byte(translated, OP_INIT_CALL);
|
|
||||||
push_instruction_code(translated, operation->to_operate_on.size);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
|
if (operation->operation == TOKEN_OR) push_instruction_byte(translated, OP_NOT);
|
||||||
|
|
||||||
|
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
jump_to_if_false[i] = push_instruction_code(translated, 0);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
||||||
|
set_instruction_code(translated, jump_to_if_false[i],
|
||||||
|
translated->bytecode.size);
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
|
||||||
|
free(jump_to_if_false);
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
|
uint8_t registerB = translated->registerAssignment++;
|
||||||
|
set_registers(translated, translated->registerAssignment);
|
||||||
|
uint64_t first = translate_parsed(
|
||||||
|
translated, darray_get(&operation->to_operate_on, 0), err);
|
||||||
|
if (err->exists)
|
||||||
|
return first;
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
for (size_t i = 1; i < operation->to_operate_on.size; i++) {
|
||||||
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
|
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
if (err->exists)
|
||||||
push_instruction_code(translated, i);
|
return first;
|
||||||
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerB);
|
||||||
|
switch (operation->operation) {
|
||||||
|
case TOKEN_PLUS:;
|
||||||
|
push_instruction_byte(translated, OP_ADDITION);
|
||||||
|
break;
|
||||||
|
case TOKEN_MINUS:;
|
||||||
|
push_instruction_byte(translated, OP_SUBTRACTION);
|
||||||
|
break;
|
||||||
|
case TOKEN_STAR:;
|
||||||
|
push_instruction_byte(translated, OP_MULTIPLICATION);
|
||||||
|
break;
|
||||||
|
case TOKEN_SLASH:;
|
||||||
|
push_instruction_byte(translated, OP_DIVISION);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*err = create_err(operation->line, operation->column, operation->length,
|
||||||
|
translated->path, "Syntax Error", "unknown operation");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, registerB);
|
||||||
|
push_instruction_byte(
|
||||||
|
translated, operation->to_operate_on.size - 1 == i ? 0 : registerA);
|
||||||
}
|
}
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
push_instruction_byte(translated, registerA);
|
||||||
push_instruction_code(translated, operation->line);
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
push_instruction_code(translated, operation->column);
|
push_instruction_byte(translated, registerB);
|
||||||
push_instruction_code(translated, operation->length);
|
translated->registerAssignment -= 2;
|
||||||
push_instruction_byte(translated, OP_CALL);
|
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,12 @@
|
|||||||
|
|
||||||
#include "translator.h"
|
#include "translator.h"
|
||||||
#include "../hash_data/hash_data.h"
|
#include "../hash_data/hash_data.h"
|
||||||
|
#include "../parser/dictionary/dictionary.h"
|
||||||
|
#include "../parser/not/not.h"
|
||||||
#include "access/access.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 "call/call.h"
|
||||||
#include "declaration/declaration.h"
|
#include "declaration/declaration.h"
|
||||||
#include "dowrap/dowrap.h"
|
#include "dowrap/dowrap.h"
|
||||||
@@ -17,6 +22,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 +55,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 +86,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 +151,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);
|
||||||
@@ -159,9 +165,83 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
|
|||||||
err);
|
err);
|
||||||
case AST_ACCESS:
|
case AST_ACCESS:
|
||||||
return translate_access(translated, (ParsedAccess *)parsedValue->data, err);
|
return translate_access(translated, (ParsedAccess *)parsedValue->data, err);
|
||||||
|
case AST_ITEM_ACCESS:
|
||||||
|
return translate_item_access(translated, (ParsedItemAccess *)parsedValue->data, err);
|
||||||
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;
|
||||||
|
}
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,24 +24,30 @@ 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_LOAD_MULTIPLY_FUNCTION,
|
OP_ADDITION,
|
||||||
OP_LOAD_DIVISION_FUNCTION
|
OP_SUBTRACTION,
|
||||||
|
OP_LOAD_GETATTRIBUTE_METHOD,
|
||||||
|
OP_MULTIPLICATION,
|
||||||
|
OP_DIVISION,
|
||||||
|
OP_NOT,
|
||||||
|
OP_LOAD_SETATTR_METHOD,
|
||||||
|
OP_CREATE_DICTIONARY,
|
||||||
|
OP_LOAD_GETITEM_METHOD,
|
||||||
|
OP_LOAD_SETITEM_METHOD
|
||||||
} OperationType;
|
} OperationType;
|
||||||
|
|
||||||
void arena_resize(ConstantArena *arena, size_t new_size);
|
void arena_resize(ConstantArena *arena, size_t new_size);
|
||||||
|
|
||||||
void *arena_get(ConstantArena *arena, size_t offset);
|
|
||||||
|
|
||||||
size_t arena_push(ConstantArena *arena, const void *data, size_t length);
|
size_t arena_push(ConstantArena *arena, const void *data, size_t length);
|
||||||
|
|
||||||
size_t push_instruction_byte(Translated *translator, uint8_t byte);
|
size_t push_instruction_byte(Translated *translator, uint8_t byte);
|
||||||
|
|||||||
55
src/translator/while/while.c
Normal file
55
src/translator/while/while.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "while.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile,
|
||||||
|
ArErr *err) {
|
||||||
|
set_registers(translated, 1);
|
||||||
|
DArray return_jumps;
|
||||||
|
DArray *old_return_jumps = NULL;
|
||||||
|
if (translated->return_jumps) {
|
||||||
|
darray_init(&return_jumps, sizeof(size_t));
|
||||||
|
old_return_jumps = translated->return_jumps;
|
||||||
|
translated->return_jumps = &return_jumps;
|
||||||
|
}
|
||||||
|
size_t first = push_instruction_byte(translated, OP_NEW_SCOPE);
|
||||||
|
size_t start_of_loop =
|
||||||
|
translate_parsed(translated, parsedWhile->condition, err);
|
||||||
|
if (err->exists) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, OP_BOOL);
|
||||||
|
push_instruction_byte(translated, OP_JUMP_IF_FALSE);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
uint64_t jump_index = push_instruction_code(translated, 0);
|
||||||
|
translate_parsed(translated, parsedWhile->content, err);
|
||||||
|
push_instruction_byte(translated, OP_EMPTY_SCOPE);
|
||||||
|
push_instruction_byte(translated, OP_JUMP);
|
||||||
|
push_instruction_code(translated, start_of_loop);
|
||||||
|
set_instruction_code(translated, jump_index, translated->bytecode.size);
|
||||||
|
push_instruction_byte(translated, OP_POP_SCOPE);
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
|
push_instruction_byte(translated, 0);
|
||||||
|
if (translated->return_jumps) {
|
||||||
|
push_instruction_byte(translated, OP_JUMP);
|
||||||
|
size_t skip_return = push_instruction_code(translated, 0);
|
||||||
|
|
||||||
|
size_t return_jump_to = push_instruction_byte(translated, OP_POP_SCOPE);
|
||||||
|
push_instruction_byte(translated, OP_JUMP);
|
||||||
|
size_t return_up = push_instruction_code(translated, 0);
|
||||||
|
darray_push(old_return_jumps, &return_up);
|
||||||
|
for (size_t i = 0; i < return_jumps.size; i++) {
|
||||||
|
size_t *index = darray_get(&return_jumps, i);
|
||||||
|
set_instruction_code(translated, *index, return_jump_to);
|
||||||
|
}
|
||||||
|
set_instruction_code(translated, skip_return, translated->bytecode.size);
|
||||||
|
darray_free(&return_jumps, NULL);
|
||||||
|
translated->return_jumps = old_return_jumps;
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
15
src/translator/while/while.h
Normal file
15
src/translator/while/while.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 William Bell
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TRANSLATE_WHILE_H
|
||||||
|
#define TRANSLATE_WHILE_H
|
||||||
|
#include "../translator.h"
|
||||||
|
#include "../../parser/while/while.h"
|
||||||
|
|
||||||
|
size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile,
|
||||||
|
ArErr *err);
|
||||||
|
|
||||||
|
#endif // TRANSLATE_WHILE_H
|
||||||
94
test.ar
94
test.ar
@@ -1,94 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
"h"
|
|
||||||
"e"
|
|
||||||
"ll"
|
|
||||||
"o"
|
|
||||||
" "
|
|
||||||
"wo"
|
|
||||||
"rl"
|
|
||||||
"d"
|
|
||||||
"world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello world"
|
|
||||||
"hello\u0000world"
|
|
||||||
"🇬🇧"
|
|
||||||
"\u0000"
|
|
||||||
"hello"
|
|
||||||
|
|
||||||
let hello = "helllo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbruhhhhh"
|
|
||||||
|
|
||||||
1.24323234e2312324
|
|
||||||
|
|
||||||
let a,
|
|
||||||
b = "hello",
|
|
||||||
c,
|
|
||||||
d = 42,
|
|
||||||
temp_result,
|
|
||||||
compute_area(radius) = 3.1415,
|
|
||||||
identity(x) = x,
|
|
||||||
f(x)=do
|
|
||||||
term.log("hello world")
|
|
||||||
do
|
|
||||||
term.log('hello world')
|
|
||||||
term.log("hello world")
|
|
||||||
,
|
|
||||||
g(y, z),
|
|
||||||
result,
|
|
||||||
z = 0,
|
|
||||||
extremely_long_variable_name_to_test_limits,
|
|
||||||
cache_value = compute_area(5),
|
|
||||||
placeholder_fn_with_no_body(arg1, arg2, arg3),
|
|
||||||
total = identity(100),
|
|
||||||
deeply_nested_args_function(arg1, arg2, arg3, arg4, arg5),
|
|
||||||
sum = a,
|
|
||||||
another,
|
|
||||||
another_function(),
|
|
||||||
just_null_here,
|
|
||||||
x
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (x) do
|
|
||||||
term.log("hello world")
|
|
||||||
term.log("hello world")
|
|
||||||
else term.log("bruh")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mm=x/2/4/2/4354/534/534//534//3422*404203420234+3432423324&&430234230||4320423040230423^384239423043024923%4432042304920.3432423423
|
|
||||||
|
|
||||||
let X = [
|
|
||||||
'hello world',
|
|
||||||
'wow',
|
|
||||||
10
|
|
||||||
]
|
|
||||||
|
|
||||||
term.log(x[0:1:1])
|
|
||||||
|
|
||||||
let y = {
|
|
||||||
'hello':test,
|
|
||||||
world:'nice'
|
|
||||||
}
|
|
||||||
|
|
||||||
term.log(y['hello'],y.world)
|
|
||||||
38
test.py
38
test.py
@@ -1,38 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2025 William Bell
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
import string
|
|
||||||
from itertools import product
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def generate_names(max_width, skip_keywords=None):
|
|
||||||
if skip_keywords is None:
|
|
||||||
skip_keywords = {"if", "else", "while", "forever", "for", "break", "continue",
|
|
||||||
"return", "let", "import", "from", "do", "true", "false", "null",
|
|
||||||
"delete", "not", "try", "catch", "in", "or", "and", "elif"}
|
|
||||||
else:
|
|
||||||
skip_keywords = set(skip_keywords)
|
|
||||||
|
|
||||||
chars = string.ascii_lowercase
|
|
||||||
first = True
|
|
||||||
write = sys.stdout.write
|
|
||||||
|
|
||||||
for length in range(1, max_width + 1):
|
|
||||||
print(length, file=sys.stderr)
|
|
||||||
i = 0
|
|
||||||
for p in product(chars, repeat=length):
|
|
||||||
name = ''.join(p)
|
|
||||||
if name in skip_keywords:
|
|
||||||
continue
|
|
||||||
write('let ')
|
|
||||||
write(name)
|
|
||||||
write(' = null\n')
|
|
||||||
first = False
|
|
||||||
if i>10000000:
|
|
||||||
break
|
|
||||||
i+=1
|
|
||||||
|
|
||||||
# Example usage:
|
|
||||||
max_width = 5
|
|
||||||
generate_names(max_width)
|
|
||||||
15
testing.ar
15
testing.ar
@@ -1,15 +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"))
|
|
||||||
|
|
||||||
let a = 9
|
|
||||||
let b = 10
|
|
||||||
|
|
||||||
term.log(string(a)+'+'+string(b)+'='+string(a+b))
|
|
||||||
9
tests/anonymous_function.ar
Normal file
9
tests/anonymous_function.ar
Normal file
@@ -0,0 +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
|
||||||
1
tests/env.ar
Normal file
1
tests/env.ar
Normal file
@@ -0,0 +1 @@
|
|||||||
|
term.log("hello,", env.USER+'.', 'how is', env.XDG_SESSION_TYPE+'?')
|
||||||
10
tests/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)
|
||||||
10
tests/intergral.ar
Normal file
10
tests/intergral.ar
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
let f(x) = sin(x)
|
||||||
|
|
||||||
|
let intergral_aprox(n, a, b) = do
|
||||||
|
let h = (b-a)/n
|
||||||
|
let output = 0
|
||||||
|
for (i from 1 to n+1) do
|
||||||
|
output += h*f(a+i*h)
|
||||||
|
return output
|
||||||
|
|
||||||
|
term.log(intergral_aprox(1000, 0,1))
|
||||||
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
|
||||||
6
tests/number-memory-leak.ar
Normal file
6
tests/number-memory-leak.ar
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
let i = 10
|
||||||
|
let x = 1
|
||||||
|
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*n
|
||||||
|
term.log(i=i-1)
|
||||||
Reference in New Issue
Block a user