Compare commits

...

22 Commits

Author SHA1 Message Date
8b2eedf589 load cache if it exists 2025-07-05 04:38:37 +01:00
48647f3734 load cache if it exists 2025-07-05 04:38:28 +01:00
47379a2621 Remove old xxHash submodule 2025-07-01 15:11:34 +01:00
246e20014f add file hashing for cache validation and provide the license to the cc0 files in the project 2025-07-01 04:28:32 +01:00
c31f16d68d add file hashing for cache validation 2025-07-01 04:28:03 +01:00
49ae0223cb change gentest to be written in python for speed build faster while chloride isnt in a finished state 2025-07-01 01:19:23 +01:00
d868de4ab9 remove big test files 2025-06-30 17:57:03 +01:00
3adecb4eba use hashmap in constants buffer to speed up translation time with large files 2025-06-30 17:56:32 +01:00
31f38d8ba4 fix translation taking a while if constants buffer is big 2025-06-28 16:17:46 +01:00
aa65393e2c change to uint8_t for bytecode to reduce wasted bytes 2025-06-27 06:07:57 +01:00
358127a145 fix memory leak in operations 2025-06-26 18:08:17 +01:00
6828cc5f1a fix memory leak in declaration and function 2025-06-26 16:56:17 +01:00
a9d0ba0318 add function object 2025-06-26 05:11:34 +01:00
a275a0a0ad add functions to bytecode and continuing working on runtime objects 2025-06-25 04:59:09 +01:00
4f757cd9b8 print with embeded nulls 2025-06-24 03:57:38 +01:00
908d627962 add null object and add load const 2025-06-24 03:49:05 +01:00
498cd39c04 start creating base objects for runtime 2025-06-24 01:55:01 +01:00
74c71c3a1b start working on oop runtime 2025-06-22 19:00:03 +01:00
fcffdc9000 test const buffer compression 2025-06-22 15:01:12 +01:00
d1f9b8a334 work on hashmap 2025-06-20 03:00:56 +01:00
bddfb59886 start working on runtime 2025-06-20 02:50:05 +01:00
e5e4f22481 write bytecode debugging script and start working on functions 2025-06-15 05:05:33 +01:00
60 changed files with 1899 additions and 229 deletions

2
.gitignore vendored
View File

@@ -61,3 +61,5 @@ build
*.yy.h
out.arbin
rand_test.ar
__arcache__

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "external/xxhash"]
path = external/xxhash
url = https://github.com/Cyan4973/xxHash.git

View File

@@ -1,3 +1,7 @@
This project is licensed under the GNU General Public License version 3 (GPLv3), except for
some files (e.g., in the `src/hash_data/siphash/` directory) which are licensed under CC0 1.0 Universal.
See the LICENSE-CC0 file in the respective directories for details.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

View File

@@ -2,7 +2,7 @@ LEXER_SRC = src/lexer/lex.l
LEXER_C = src/lexer/lex.yy.c
LEXER_H = src/lexer/lex.yy.h
CFILES = $(shell find src -name '*.c')
CFILES = external/xxhash/xxhash.c $(shell find src -name '*.c')
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function
BINARY = bin/argon
@@ -26,7 +26,7 @@ full-debug: $(CFILES) $(LEXER_C) $(LEXER_H)
optimised: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin
gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS)
${BINARY} test.ar
${BINARY} rand_test.ar
gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS)

126
debug_arbin.py Normal file
View File

@@ -0,0 +1,126 @@
import struct
from enum import Enum, EnumMeta, auto
class AutoEnumMeta(EnumMeta):
@classmethod
def __prepare__(metacls, clsname, bases, **kwargs):
d = super().__prepare__(clsname, bases, **kwargs)
d['_next_value'] = 254
return d
def _generate_next_value_(cls, name, start, count, last_values):
value = cls._next_value
cls._next_value += 1
return value
class OperationType(Enum, metaclass=AutoEnumMeta):
OP_LOAD_CONST = auto()
OP_DECLARE = auto()
OP_LOAD_NULL = auto()
OP_JUMP = auto()
class Types(Enum, metaclass=AutoEnumMeta):
TYPE_OP_STRING = auto()
TYPE_OP_NUMBER = auto()
def read_arbin(filename):
with open(filename, "rb") as f:
# Read and verify file identifier (4 bytes)
file_id = f.read(4)
if file_id != b"ARBI":
raise ValueError("Invalid file identifier")
# Read version number (uint64_t, little-endian)
version_number, = struct.unpack("<Q", f.read(8))
# Read regCount, constantsSize, bytecodeSize (all uint64_t, little-endian)
reg_count, = struct.unpack("<Q", f.read(8))
constants_size, = struct.unpack("<Q", f.read(8))
bytecode_size, = struct.unpack("<Q", f.read(8))
# Read constants buffer (raw bytes)
constants = f.read(constants_size)
# Read bytecode array (uint64_t, little-endian)
bytecode = []
for _ in range(bytecode_size):
instr, = struct.unpack("<Q", f.read(8))
bytecode.append(instr)
return {
"version": version_number,
"register_count": reg_count,
"constants_size": constants_size,
"bytecode_size": bytecode_size,
"constants": constants,
"bytecode": bytecode,
}
class print_opcode:
def start(registers,data, i):
print()
match data['bytecode'][i]:
case OperationType.OP_LOAD_CONST.value:
return print_opcode.OP_LOAD_CONST(registers,data, i)
case OperationType.OP_DECLARE.value:
return print_opcode.OP_DECLARE(registers,data, i)
case OperationType.OP_LOAD_NULL.value:
return print_opcode.OP_LOAD_NULL(registers,data, i)
def OP_LOAD_CONST(registers,data, i) -> int:
print("OP_LOAD_CONST ", end="")
i+=1
register = data["bytecode"][i]
print("To Register",register,"", end="")
i+=1
match data["bytecode"][i]:
case Types.TYPE_OP_STRING.value:
print("TYPE_OP_STRING ", end="")
case Types.TYPE_OP_NUMBER.value:
print("TYPE_OP_NUMBER ", end="")
i+=1
length = data["bytecode"][i]
i+=1
offset = data["bytecode"][i]
i+=1
print("Length",length,"", end="")
print("Offset",offset,"")
registers[register] = data["constants"][offset:offset+length].decode()
print("const value:", registers[register])
return i
def OP_DECLARE(registers,data, i) -> int:
print("OP_DECLARE ", end="")
i+=1
length = data["bytecode"][i]
i+=1
offset = data["bytecode"][i]
i+=1
from_register = data["bytecode"][i]
i+=1
print("Name Length",length,"", end="")
print("Name Offset",offset,"", end="")
print("From Register",from_register,"")
print("output: let", data['constants'][offset:offset+length].decode(),'=',registers[from_register])
return i
def OP_LOAD_NULL(registers,data, i) -> int:
print("OP_LOAD_NULL ", end="")
i+=1
to_register = data["bytecode"][i]
i+=1
print("To Register",to_register,"")
registers[to_register] = "null"
return i
if __name__ == "__main__":
filename = "out.arbin"
data = read_arbin(filename)
print(f"Version: {data['version']}")
print(f"Register Count: {data['register_count']}")
print(f"Constants Size: {data['constants_size']} bytes")
print(f"Bytecode Length: {data['bytecode_size']} elements")
registers = ["null"]*data['register_count']
i=0
while i<len(data["bytecode"]):
i=print_opcode.start(registers,data,i)

1
external/xxhash vendored Submodule

Submodule external/xxhash added at 38d555879f

7
gentest.py Normal file
View File

@@ -0,0 +1,7 @@
import random
myfile = open("rand_test.ar","w")
for i in range(10000000):
myfile.write("\"")
myfile.write(str(random.random())[2::])
myfile.write("\"\n")

View File

@@ -4,7 +4,7 @@
#include <stdbool.h>
#include <stddef.h> // for size_t
#define CHUNK_SIZE 1024
#define CHUNK_SIZE 1048576
typedef struct {
void *data;

28
src/hash_data/hash_data.c Normal file
View File

@@ -0,0 +1,28 @@
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include "siphash/siphash.h"
#include "hash_data.h"
uint8_t siphash_key[16];
uint8_t empty_siphash_key[16];
void generate_siphash_key(uint8_t hash_key[16]) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0 || read(fd, hash_key, 16) != 16) {
// Fallback or abort
}
close(fd);
}
uint64_t siphash64_bytes(const void *data, size_t len,uint8_t hash_key[16]) {
uint8_t out[8];
if (siphash(data, len, hash_key, out, sizeof(out)) != 0)
return 0;
uint64_t hash = 0;
for (int i = 0; i < 8; ++i)
hash |= ((uint64_t)out[i]) << (8 * i);
return hash;
}

11
src/hash_data/hash_data.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef HASH_DATA_H
#define HASH_DATA_H
#include <stdlib.h>
#include <stdint.h>
extern uint8_t siphash_key[16];
extern uint8_t empty_siphash_key[16];
void generate_siphash_key(uint8_t siphash_key[16]);
uint64_t siphash64_bytes(const void *data, size_t len,uint8_t siphash_key[16]);
#endif //HASH_DATA_H

View File

@@ -0,0 +1,122 @@
This license applies **only** to the files that explicitly state at the top of the file that they are under CC0 1.0 Universal.
All other files in this project are licensed under the GNU General Public License version 3 (GPLv3) unless otherwise stated.
Please refer to the LICENSE file in the root directory for the main project license.
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

View File

@@ -0,0 +1,189 @@
/*
* This file is dedicated to the public domain under CC0 1.0 Universal.
* See the LICENSE-CC0 file in this directory for details.
*
* SipHash reference C implementation
*
* Copyright (c) 2012-2022 Jean-Philippe Aumasson
* <jeanphilippe.aumasson@gmail.com>
* Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*
* SPDX-License-Identifier: CC0-1.0
*/
#include "siphash.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
/* default: SipHash-2-4 */
#ifndef cROUNDS
#define cROUNDS 2
#endif
#ifndef dROUNDS
#define dROUNDS 4
#endif
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
#define U32TO8_LE(p, v) \
(p)[0] = (uint8_t)((v)); \
(p)[1] = (uint8_t)((v) >> 8); \
(p)[2] = (uint8_t)((v) >> 16); \
(p)[3] = (uint8_t)((v) >> 24);
#define U64TO8_LE(p, v) \
U32TO8_LE((p), (uint32_t)((v))); \
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
#define U8TO64_LE(p) \
(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
#define SIPROUND \
do { \
v0 += v1; \
v1 = ROTL(v1, 13); \
v1 ^= v0; \
v0 = ROTL(v0, 32); \
v2 += v3; \
v3 = ROTL(v3, 16); \
v3 ^= v2; \
v0 += v3; \
v3 = ROTL(v3, 21); \
v3 ^= v0; \
v2 += v1; \
v1 = ROTL(v1, 17); \
v1 ^= v2; \
v2 = ROTL(v2, 32); \
} while (0)
#ifdef DEBUG_SIPHASH
#include <stdio.h>
#define TRACE \
do { \
printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \
printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \
printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \
printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \
} while (0)
#else
#define TRACE
#endif
/*
Computes a SipHash value
*in: pointer to input data (read-only)
inlen: input data length in bytes (any size_t value)
*k: pointer to the key data (read-only), must be 16 bytes
*out: pointer to output data (write-only), outlen bytes must be allocated
outlen: length of the output in bytes, must be 8 or 16
*/
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
const size_t outlen) {
const unsigned char *ni = (const unsigned char *)in;
const unsigned char *kk = (const unsigned char *)k;
assert((outlen == 8) || (outlen == 16));
uint64_t v0 = UINT64_C(0x736f6d6570736575);
uint64_t v1 = UINT64_C(0x646f72616e646f6d);
uint64_t v2 = UINT64_C(0x6c7967656e657261);
uint64_t v3 = UINT64_C(0x7465646279746573);
uint64_t k0 = U8TO64_LE(kk);
uint64_t k1 = U8TO64_LE(kk + 8);
uint64_t m;
int i;
const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
const int left = inlen & 7;
uint64_t b = ((uint64_t)inlen) << 56;
v3 ^= k1;
v2 ^= k0;
v1 ^= k1;
v0 ^= k0;
if (outlen == 16)
v1 ^= 0xee;
for (; ni != end; ni += 8) {
m = U8TO64_LE(ni);
v3 ^= m;
TRACE;
for (i = 0; i < cROUNDS; ++i)
SIPROUND;
v0 ^= m;
}
switch (left) {
case 7:
b |= ((uint64_t)ni[6]) << 48;
/* FALLTHRU */
case 6:
b |= ((uint64_t)ni[5]) << 40;
/* FALLTHRU */
case 5:
b |= ((uint64_t)ni[4]) << 32;
/* FALLTHRU */
case 4:
b |= ((uint64_t)ni[3]) << 24;
/* FALLTHRU */
case 3:
b |= ((uint64_t)ni[2]) << 16;
/* FALLTHRU */
case 2:
b |= ((uint64_t)ni[1]) << 8;
/* FALLTHRU */
case 1:
b |= ((uint64_t)ni[0]);
break;
case 0:
break;
}
v3 ^= b;
TRACE;
for (i = 0; i < cROUNDS; ++i)
SIPROUND;
v0 ^= b;
if (outlen == 16)
v2 ^= 0xee;
else
v2 ^= 0xff;
TRACE;
for (i = 0; i < dROUNDS; ++i)
SIPROUND;
b = v0 ^ v1 ^ v2 ^ v3;
U64TO8_LE(out, b);
if (outlen == 8)
return 0;
v1 ^= 0xdd;
TRACE;
for (i = 0; i < dROUNDS; ++i)
SIPROUND;
b = v0 ^ v1 ^ v2 ^ v3;
U64TO8_LE(out + 8, b);
return 0;
}

View File

@@ -0,0 +1,26 @@
/*
* This file is dedicated to the public domain under CC0 1.0 Universal.
* See the LICENSE-CC0 file in this directory for details.
*
* SipHash reference C implementation
*
* Copyright (c) 2012-2022 Jean-Philippe Aumasson
* <jeanphilippe.aumasson@gmail.com>
* Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <inttypes.h>
#include <string.h>
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out,
const size_t outlen);

View File

@@ -1,80 +1,130 @@
#include "hashmap.h"
#include <stdlib.h>
#include "../memory.h"
struct table *createTable(int size)
{
struct table *t = (struct table *)checked_malloc(sizeof(struct table));
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
struct hashmap *createHashmap() {
size_t size = 8;
struct hashmap *t = (struct hashmap *)checked_malloc(sizeof(struct hashmap));
t->size = size;
t->order = 1;
t->list = (struct node **)checked_malloc(sizeof(struct node *) * size);
int i;
for (i = 0; i < size; i++)
t->list[i] = NULL;
memset(t->list, 0, sizeof(struct node *) * size);
return t;
}
int hashCode(struct table *t, int key)
{
if (key < 0)
return -(key % t->size);
return key % t->size;
void hashmap_free(struct hashmap *t, free_val_func free_val) {
if (!t) return;
for (size_t i = 0; i < t->size; i++) {
struct node *current = t->list[i];
while (current) {
struct node *next = current->next;
if (free_val && current->val) {
free_val(current->val);
}
free(current);
current = next;
}
}
free(t->list);
free(t);
}
int remove(struct table *t, int key)
{
int pos = hashCode(t, key);
void resize_hashmap(struct hashmap *t) {
int old_size = t->size;
int new_size = old_size * 2;
struct node **old_list = t->list;
// Create new list
t->list = (struct node **)checked_malloc(sizeof(struct node *) * new_size);
memset(t->list, 0, sizeof(struct node *) * new_size);
t->size = new_size;
t->count = 0;
// Rehash old entries into new list
for (int i = 0; i < old_size; i++) {
struct node *temp = old_list[i];
while (temp) {
hashmap_insert(t, temp->hash, temp->key, temp->val,
temp->order); // Will increment count
temp = temp->next;
}
}
free(old_list);
}
int hashCode(struct hashmap *t, uint64_t hash) { return hash % t->size; }
int hashmap_remove(struct hashmap *t, uint64_t hash) {
int pos = hashCode(t, hash);
struct node *list = t->list[pos];
struct node *temp = list;
struct node *prev = NULL;
while (temp)
{
if (temp->key == key)
{
while (temp) {
if (temp->hash == hash) {
if (prev)
prev->next = temp->next;
else
t->list[pos] = temp->next;
free(temp);
return 1;
}
prev = temp;
temp = temp->next;
}
list = NULL;
prev = NULL;
temp = NULL;
return 0;
}
void insert(struct table *t, int key, void* val)
{
int pos = hashCode(t, key);
void hashmap_insert(struct hashmap *t, uint64_t hash, void *key,
void *val, size_t order) {
if (!order) {
order = t->order++;
}
if ((t->count + 1) > t->size * 0.75) {
resize_hashmap(t);
}
int pos = hashCode(t, hash);
struct node *list = t->list[pos];
struct node *newNode = (struct node *)checked_malloc(sizeof(struct node));
struct node *temp = list;
while (temp)
{
if (temp->key == key)
{
// Check if key exists → overwrite
while (temp) {
if (temp->hash == hash) {
temp->val = val;
return;
}
temp = temp->next;
}
// Insert new node
struct node *newNode = (struct node *)checked_malloc(sizeof(struct node));
newNode->hash = hash;
newNode->key = key;
newNode->val = val;
newNode->order = order;
newNode->next = list;
t->list[pos] = newNode;
t->count++;
}
void *lookup(struct table *t, int key)
{
int pos = hashCode(t, key);
void *hashmap_lookup(struct hashmap *t, uint64_t hash) {
int pos = hashCode(t, hash);
struct node *list = t->list[pos];
struct node *temp = list;
while (temp)
{
if (temp->key == key)
{
while (temp) {
if (temp->hash == hash) {
return temp->val;
}
temp = temp->next;

View File

@@ -1,24 +1,37 @@
#ifndef HASHMAP_H
#define HASHMAP_H
#include <stdint.h>
#include <stdlib.h>
struct node
{
int key;
typedef struct ArgonObject ArgonObject;
typedef void (*free_val_func)(void *val);
struct node {
uint64_t hash;
void *key;
void *val;
size_t order;
struct node *next;
};
struct table
{
int size;
struct hashmap {
size_t size;
size_t count;
size_t order;
struct node **list;
};
struct table *createTable(int size);
struct hashmap *createHashmap();
int hashCode(struct table *t, int key);
void hashmap_free(struct hashmap *t, free_val_func free_val);
int remove(struct table *t, int key);
int hashCode(struct hashmap *t, uint64_t hash);
void insert(struct table *t, int key, void* val);
int hashmap_remove(struct hashmap *t, uint64_t hash);
void hashmap_insert(struct hashmap *t, uint64_t hash, void *key,
void *val, size_t order);
void *hashmap_lookup(struct hashmap *t, uint64_t hash);
#endif // HASHMAP_H

View File

@@ -3,68 +3,324 @@
#include "lexer/token.h"
#include "memory.h"
#include "parser/parser.h"
#include "runtime/runtime.h"
#include "translator/translator.h"
#include "../external/xxhash/xxhash.h"
#include "hash_data/hash_data.h"
#include <arpa/inet.h>
#include <endian.h>
#include <string.h>
#include <locale.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifdef _WIN32
#include <direct.h>
#define mkdir(path, mode) _mkdir(path)
#else
#include <sys/stat.h>
#include <sys/types.h>
#endif
#include <string.h>
const char FILE_IDENTIFIER[] = "ARBI";
const uint64_t version_number = 0;
int ensure_dir_exists(const char *path) {
struct stat st = {0};
if (stat(path, &st) == -1) {
// Directory does not exist, create it
if (mkdir(path, 0755) != 0) {
perror("mkdir failed");
return -1;
}
}
return 0;
}
char *normalize_path(char *path) {
#ifdef _WIN32
for (char *p = path; *p; p++) {
if (*p == '/') {
*p = '\\';
}
}
#endif
return path;
}
// Join two paths using '/' as separator, no platform checks here.
int path_join(char *dest, size_t dest_size, const char *path1,
const char *path2) {
size_t len1 = strlen(path1);
size_t len2 = strlen(path2);
// Check if buffer is large enough (extra 2 for '/' and '\0')
if (len1 + len2 + 2 > dest_size)
return -1;
strcpy(dest, path1);
// Add '/' if needed
if (len1 > 0 && dest[len1 - 1] != '/') {
dest[len1] = '/';
dest[len1 + 1] = '\0';
len1++;
}
// Skip leading '/' in path2 to avoid double separator
if (len2 > 0 && path2[0] == '/') {
path2++;
len2--;
}
strcat(dest, path2);
return 0;
}
const char CACHE_FOLDER[] = "__arcache__";
const char FILE_IDENTIFIER[5] = "ARBI";
const char BYTECODE_EXTENTION[] = "arbin";
const uint32_t version_number = 0;
#ifdef _WIN32
#define PATH_SEP '\\'
#else
#define PATH_SEP '/'
#endif
char *replace_extension(const char *path, const char *new_ext) {
// Defensive: if new_ext doesn't start with '.', add it
int need_dot = (new_ext[0] != '.');
// Find last path separator to avoid changing dots in folder names
const char *last_sep = strrchr(path, PATH_SEP);
#ifdef _WIN32
// Windows can have '/' too as separator in practice, check it
const char *last_alt_sep = strrchr(path, '/');
if (last_alt_sep && (!last_sep || last_alt_sep > last_sep)) {
last_sep = last_alt_sep;
}
#endif
// Find last '.' after last_sep (if any)
const char *last_dot = strrchr(path, '.');
if (last_dot && (!last_sep || last_dot > last_sep)) {
// Extension found: copy path up to last_dot, then append new_ext
size_t base_len = last_dot - path;
size_t ext_len = strlen(new_ext) + (need_dot ? 1 : 0);
size_t new_len = base_len + ext_len + 1;
char *result = malloc(new_len);
if (!result)
return NULL;
memcpy(result, path, base_len);
if (need_dot)
result[base_len] = '.';
strcpy(result + base_len + (need_dot ? 1 : 0), new_ext);
return result;
} else {
// No extension found: append '.' + new_ext (if needed)
size_t path_len = strlen(path);
size_t ext_len = strlen(new_ext) + (need_dot ? 1 : 0);
size_t new_len = path_len + ext_len + 1;
char *result = malloc(new_len);
if (!result)
return NULL;
strcpy(result, path);
if (need_dot)
strcat(result, ".");
strcat(result, new_ext);
return result;
}
}
int load_cache(Translated *translated_dest, char *joined_paths, uint64_t hash) {
FILE *bytecode_file = fopen(joined_paths, "rb");
if (!bytecode_file)
return 1;
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)];
file_identifier_from_cache[strlen(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) {
fclose(bytecode_file);
return 1;
}
uint32_t read_version;
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
sizeof(read_version)) {
goto FAILED;
}
read_version = le32toh(read_version);
if (read_version != version_number) {
goto FAILED;
}
uint64_t read_hash;
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
sizeof(read_hash)) {
goto FAILED;
}
read_hash = le64toh(read_hash);
if (read_hash != hash) {
goto FAILED;
}
uint8_t register_count;
if (fread(&register_count, 1, sizeof(register_count), bytecode_file) !=
sizeof(register_count)) {
goto FAILED;
}
uint64_t constantsSize;
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
sizeof(constantsSize)) {
goto FAILED;
}
constantsSize = le64toh(constantsSize);
uint64_t bytecodeSize;
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
sizeof(bytecodeSize)) {
goto FAILED;
}
bytecodeSize = le64toh(bytecodeSize);
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;
}
translated_dest->registerCount = register_count;
fclose(bytecode_file);
return 0;
FAILED:
fclose(bytecode_file);
return 1;
}
int main(int argc, char *argv[]) {
generate_siphash_key(siphash_key);
clock_t start, end;
double time_spent, total_time_spent = 0;
setlocale(LC_ALL, "");
if (argc <= 1)
return -1;
ar_memory_init();
char *path = argv[1];
DArray tokens;
darray_init(&tokens, sizeof(Token));
FILE *file = fopen(path, "r");
if (!file) {
return -1;
}
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);
char *filename_without_extention =
replace_extension(path, BYTECODE_EXTENTION);
size_t joined_paths_length =
strlen(CACHE_FOLDER) + strlen(filename_without_extention) + 2;
char *joined_paths = checked_malloc(joined_paths_length);
path_join(joined_paths, joined_paths_length, CACHE_FOLDER,
filename_without_extention);
free(filename_without_extention);
filename_without_extention = NULL;
Translated translated = init_translator();
if (load_cache(&translated, joined_paths, hash) != 0) {
free_translator(&translated);
translated = init_translator();
DArray tokens;
darray_init(&tokens, sizeof(Token));
LexerState state = {path, file, 0, 0, &tokens};
start = clock();
lexer(state);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Lexer time taken: %f seconds\n", time_spent);
fclose(state.file);
DArray ast;
darray_init(&ast, sizeof(ParsedValue));
start = clock();
parser(path, &ast, &tokens, false);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Parser time taken: %f seconds\n", time_spent);
darray_free(&tokens, free_token);
Translated translated = init_translator();
start = clock();
translate(&translated, &ast);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Translation time taken: %f seconds\n", time_spent);
darray_free(&ast, free_parsed);
ensure_dir_exists(CACHE_FOLDER);
file = fopen("out.arbin", "wb");
file = fopen(joined_paths, "wb");
uint64_t regCount = (uint64_t)translated.registerCount;
uint64_t constantsSize = (uint64_t)translated.constants.size;
uint64_t bytecodeSize = (uint64_t)translated.bytecode.size;
uint64_t version_number_htole64ed = htole64(version_number);
regCount = htole64(regCount);
regCount = htole64(regCount);
uint32_t version_number_htole32ed = htole32(version_number);
uint64_t net_hash = htole64(hash);
constantsSize = htole64(constantsSize);
bytecodeSize = htole64(bytecodeSize);
fwrite(&FILE_IDENTIFIER, sizeof(char), strlen(FILE_IDENTIFIER), file);
fwrite(&version_number_htole64ed, sizeof(uint64_t), 1, file);
fwrite(&regCount, sizeof(uint64_t), 1, file);
fwrite(&version_number_htole32ed, sizeof(uint32_t), 1, file);
fwrite(&net_hash, sizeof(net_hash), 1, file);
fwrite(&translated.registerCount, sizeof(uint8_t), 1, file);
fwrite(&constantsSize, sizeof(uint64_t), 1, file);
fwrite(&bytecodeSize, sizeof(uint64_t), 1, file);
fwrite(translated.constants.data, 1, translated.constants.size, file);
@@ -72,7 +328,20 @@ int main(int argc, char *argv[]) {
translated.bytecode.size, file);
fclose(file);
}
init_types();
start = clock();
runtime(translated);
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Execution time taken: %f seconds\n", time_spent);
printf("total time taken: %f seconds\n", total_time_spent);
free_translator(&translated);
free(joined_paths);
return 0;
}

View File

@@ -1,10 +1,9 @@
#include "memory.h"
#include <gc.h>
#include <gc/gc.h>
#include <gmp.h>
#include <stdio.h>
#include <stdlib.h> // for malloc/free (temp arena fallback)
#include <string.h>
#include <stdio.h>
void *checked_malloc(size_t size) {
void *ptr = malloc(size);
@@ -20,7 +19,6 @@ void *gmp_gc_realloc(void *ptr, size_t old_size, size_t new_size) {
return GC_realloc(ptr, new_size);
}
void gmp_gc_free(void *ptr, size_t size) {
(void)size; // Boehm GC manages this itself
// No-op — memory will be collected automatically
@@ -32,9 +30,13 @@ void ar_memory_init() {
mp_set_memory_functions(GC_malloc, gmp_gc_realloc, gmp_gc_free);
}
void *ar_alloc(size_t size) { return GC_MALLOC(size); }
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
GC_finalization_proc *old_fn, void **old_client_data) {
return GC_register_finalizer_no_order(obj, fn, client_data, old_fn, old_client_data);
}
void *ar_alloc_atomic(size_t size) { return GC_MALLOC_ATOMIC(size); }
char *ar_strdup(const char *str) {

View File

@@ -2,8 +2,12 @@
#define ARGON_MEMORY_H
#include <stddef.h> // for size_t
#include <gc/gc.h>
// GC-managed allocations
void ar_finalizer(void *obj, GC_finalization_proc fn, void *client_data,
GC_finalization_proc *old_fn, void **old_client_data);
void *ar_alloc(size_t size);
void *ar_alloc_atomic(size_t size);
char *ar_strdup(const char *str);

View File

@@ -49,5 +49,6 @@ void free_parse_call(void *ptr) {
darray_free(&parsedCall->args, free_parsed);
free_parsed(parsedCall->to_call);
free(parsedCall->to_call);
free(parsedCall);
}

View File

@@ -1,6 +1,7 @@
#include "declaration.h"
#include "../../lexer/token.h"
#include "../../memory.h"
#include "../function/function.h"
#include "../literals/literals.h"
#include "../parser.h"
#include <stdio.h>
@@ -22,7 +23,8 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
darray_push(declarations, &_declaration);
ParsedSingleDeclaration *declaration =
darray_get(declarations, declarations->size - 1);
declaration->is_function = false;
bool isFunction=false;
DArray parameters;
declaration->from = parse_null();
if (token->type != TOKEN_IDENTIFIER) {
@@ -38,8 +40,8 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
return parsedValue;
token = darray_get(tokens, *index);
if (token->type == TOKEN_LPAREN) {
declaration->is_function = true;
darray_init(&declaration->parameters, sizeof(char *));
isFunction = true;
darray_init(&parameters, sizeof(char *));
(*index)++;
error_if_finished(file, tokens, index);
token = darray_get(tokens, *index);
@@ -61,9 +63,9 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
file, token->line, token->column);
exit(EXIT_FAILURE);
}
char *parameter_name =
strcpy(checked_malloc(strlen(token->value) + 1), token->value);
darray_push(&declaration->parameters, &parameter_name);
char *parameter_name = checked_malloc(strlen(token->value) + 1);
strcpy(parameter_name, token->value);
darray_push(&parameters, &parameter_name);
(*index)++;
error_if_finished(file, tokens, index);
skip_newlines_and_indents(tokens, index);
@@ -97,10 +99,15 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
token->column);
exit(EXIT_FAILURE);
}
}
if (isFunction) {
declaration->from = create_parsed_function(declaration->name, parameters,
declaration->from);
}
if ((*index) >= tokens->size)
break;
token = darray_get(tokens, *index);
}
size_t count = skip_newlines_and_indents(tokens, index);
if ((*index) >= tokens->size)
break;
@@ -127,8 +134,6 @@ void free_string(void *ptr) {
void free_single_declaration(void *ptr) {
ParsedSingleDeclaration *declaration = ptr;
free(declaration->name);
if (declaration->is_function)
darray_free(&declaration->parameters, free_string);
free_parsed(declaration->from);
free(declaration->from);
}

View File

@@ -5,8 +5,6 @@
typedef struct {
char * name;
bool is_function;
DArray parameters; // string[]
ParsedValue * from;
} ParsedSingleDeclaration;

View File

@@ -88,5 +88,5 @@ void free_parsed_dictionary(void *ptr) {
ParsedValue *parsedValue = ptr;
DArray *parsed_dictionary = parsedValue->data;
darray_free(parsed_dictionary, free_dictionary_entry);
free(parsedValue->data);
free(parsed_dictionary);
}

View File

@@ -0,0 +1,32 @@
#include "function.h"
#include "../../memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
ParsedValue *create_parsed_function(char *name, DArray parameters,
ParsedValue *body) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type=AST_FUNCTION;
ParsedFunction *parsedFunction = checked_malloc(sizeof(ParsedFunction));
parsedValue->data=parsedFunction;
parsedFunction->name=strcpy(checked_malloc(strlen(name) + 1), name);
parsedFunction->body = body;
parsedFunction->parameters=parameters;
return parsedValue;
}
void free_parameter(void *ptr) {
char** data = ptr;
free(*data);
}
void free_function(void *ptr) {
ParsedValue *parsedValue = ptr;
ParsedFunction *parsed = parsedValue->data;
free_parsed(parsed->body);
free(parsed->body);
free(parsed->name);
darray_free(&parsed->parameters, free_parameter);
free(parsed);
}

View File

@@ -0,0 +1,17 @@
#ifndef FUNCTION_H
#define FUNCTION_H
#include "../../lexer/token.h" // for Token
#include "../parser.h"
typedef struct {
char * name;
DArray parameters;
ParsedValue *body;
} ParsedFunction;
ParsedValue *create_parsed_function(char *name, DArray parameters,
ParsedValue *body);
void free_function(void *ptr);
#endif // FUNCTION_H

View File

@@ -115,5 +115,5 @@ void free_parsed_if(void *ptr) {
ParsedValue *parsedValue = ptr;
DArray *parsed_if = parsedValue->data;
darray_free(parsed_if, free_conditional);
free(parsedValue->data);
free(parsed_if);
}

View File

@@ -45,5 +45,5 @@ void free_parsed_list(void *ptr) {
ParsedValue *parsedValue = ptr;
DArray *parsed_list = parsedValue->data;
darray_free(parsed_list, free_parsed);
free(parsedValue->data);
free(parsed_list);
}

View File

@@ -6,9 +6,9 @@
#include <stdlib.h>
#include <string.h>
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) {
return darray_get(to_operate_on, 0);
return *((ParsedValue*)darray_get(to_operate_on, 0));
}
TokenType operation = 0;
DArray positions;
@@ -23,10 +23,10 @@ ParsedValue *convert_to_operation(DArray *to_operate_on, DArray *operations) {
}
darray_push(&positions, &i);
}
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_OPERATION;
ParsedValue parsedValue;
parsedValue.type = AST_OPERATION;
ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation));
parsedValue->data = operationStruct;
parsedValue.data = operationStruct;
operationStruct->operation = operation;
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
size_t last_position = 0;
@@ -37,16 +37,18 @@ ParsedValue *convert_to_operation(DArray *to_operate_on, DArray *operations) {
to_operate_on, to_operate_on_last_position, (*position) + 1);
DArray operations_slice =
darray_slice(operations, last_position, *position);
ParsedValue result = convert_to_operation(&to_operate_on_slice, &operations_slice);
darray_push(&operationStruct->to_operate_on,
convert_to_operation(&to_operate_on_slice, &operations_slice));
&result);
last_position = (*position);
to_operate_on_last_position = (*position) + 1;
}
DArray to_operate_on_slice =
darray_slice(to_operate_on, to_operate_on_last_position, to_operate_on->size);
DArray operations_slice = darray_slice(operations, last_position, operations->size);
ParsedValue result =convert_to_operation(&to_operate_on_slice, &operations_slice);
darray_push(&operationStruct->to_operate_on,
convert_to_operation(&to_operate_on_slice, &operations_slice));
&result);
darray_free(&positions, NULL);
return parsedValue;
}
@@ -80,10 +82,12 @@ ParsedValue *parse_operations(char *file, DArray *tokens, size_t *index,
darray_push(&to_operate_on, parsedValue);
free(parsedValue);
}
ParsedValue *output = convert_to_operation(&to_operate_on, &operations);
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedValue output = convert_to_operation(&to_operate_on, &operations);
memcpy(parsedValue, &output,sizeof(ParsedValue));
darray_free(&to_operate_on, NULL);
darray_free(&operations, NULL);
return output;
return parsedValue;
}
void free_operation(void *ptr) {

View File

@@ -8,6 +8,7 @@
#include "declaration/declaration.h"
#include "dictionary/dictionary.h"
#include "dowrap/dowrap.h"
#include "function/function.h"
#include "if/if.h"
#include "list/list.h"
#include "literals/literals.h"
@@ -24,7 +25,7 @@
const char *ValueTypeNames[] = {
"string", "assign", "identifier", "number", "if statement",
"access", "call", "declaration", "null", "boolean",
"do wrap", "operations", "list", "dictionary"};
"do wrap", "operations", "list", "dictionary", "function"};
void error_if_finished(char *file, DArray *tokens, size_t *index) {
if ((*index) >= tokens->size) {
@@ -232,5 +233,7 @@ void free_parsed(void *ptr) {
case AST_DICTIONARY:
free_parsed_dictionary(parsed);
break;
case AST_FUNCTION:
free_function(parsed);
}
}

View File

@@ -39,7 +39,8 @@ typedef enum {
AST_DOWRAP,
AST_OPERATION,
AST_LIST,
AST_DICTIONARY
AST_DICTIONARY,
AST_FUNCTION
} ValueType;
extern const char* ValueTypeNames[];

View File

@@ -0,0 +1,113 @@
#include "darray_armem.h"
#include "../../../memory.h"
#include <gc/gc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void darray_armem_init(darray_armem *arr, size_t element_size) {
arr->element_size = element_size;
arr->size = 0;
arr->capacity = CHUNK_SIZE;
arr->data = ar_alloc(CHUNK_SIZE * element_size);
arr->resizable = true;
if (!arr->data) {
fprintf(stderr, "darray_armem_init: allocation failed\n");
exit(EXIT_FAILURE);
}
}
void darray_armem_resize(darray_armem *arr, size_t new_size) {
if (!arr->resizable) {
fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n");
exit(EXIT_FAILURE);
}
size_t new_capacity = ((new_size + CHUNK_SIZE) / CHUNK_SIZE) * CHUNK_SIZE;
if (new_capacity != arr->capacity) {
void *new_data = ar_alloc(new_capacity * arr->element_size);
memccpy(new_data,arr->data, arr->element_size, arr->capacity);
if (!new_data) {
fprintf(stderr, "darray_armem_resize: reallocation failed\n");
exit(EXIT_FAILURE);
}
arr->data = new_data;
arr->capacity = new_capacity;
}
arr->size = new_size;
}
void darray_armem_push(darray_armem *arr, void *element) {
if (!arr->resizable) {
fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n");
exit(EXIT_FAILURE);
}
if (arr->size >= arr->capacity) {
darray_armem_resize(arr, arr->size + 1);
} else {
arr->size++;
}
void *target = (char *)arr->data + (arr->size - 1) * arr->element_size;
memcpy(target, element, arr->element_size);
}
void darray_armem_pop(darray_armem *arr, void (*free_data)(void *)) {
if (!arr->resizable) {
fprintf(stderr, "darray_armem_resize: unresizable darray_armem\n");
exit(EXIT_FAILURE);
}
if (arr->size == 0)
return;
if (free_data) {
void *target = (char *)arr->data + (arr->size-1) * arr->element_size;
free_data(target);
}
darray_armem_resize(arr, arr->size-1);
}
void *darray_armem_get(darray_armem *arr, size_t index) {
if (index >= arr->size) {
fprintf(stderr, "darray_armem_get: index out of bounds\n");
exit(EXIT_FAILURE);
}
return (char *)arr->data + index * arr->element_size;
}
darray_armem darray_armem_slice(darray_armem *arr, size_t start, size_t end) {
if (start > end || end > arr->size) {
fprintf(stderr, "darray_armem_slice: invalid slice range\n");
exit(EXIT_FAILURE);
}
darray_armem slice;
slice.data = (char *)arr->data + start * arr->element_size;
slice.size = (end - start);
slice.element_size = arr->element_size;
slice.capacity = ((slice.size + CHUNK_SIZE) / CHUNK_SIZE) * CHUNK_SIZE;
slice.resizable = false;
return slice;
}
void darray_armem_free(darray_armem *arr, void (*free_data)(void *)) {
if (!arr->resizable) {
// It's a view/slice — don't free
return;
}
if (free_data) {
for (size_t i = 0; i < arr->size; ++i) {
void *element = (char *)arr->data + i * arr->element_size;
free_data(element);
}
}
free(arr->data);
arr->data = NULL;
arr->size = 0;
arr->capacity = 0;
arr->element_size = 0;
arr->resizable = false;
}

View File

@@ -0,0 +1,37 @@
#ifndef darray_armem_H
#define darray_armem_H
#include <stdbool.h>
#include <stddef.h> // for size_t
#define CHUNK_SIZE 1048576
typedef struct {
void *data;
size_t element_size;
size_t size;
size_t capacity;
bool resizable;
} darray_armem;
// Initializes the dynamic_array
void darray_armem_init(darray_armem *arr, size_t element_size);
// Pushes an element onto the array
void darray_armem_push(darray_armem *arr, void *element);
// Pops the last element, calling `free_data` if provided
void darray_armem_pop(darray_armem *arr, void (*free_data)(void *));
// Gets a pointer to an element at index
void *darray_armem_get(darray_armem *arr, size_t index);
// Frees the entire array and optionally each element
void darray_armem_free(darray_armem *arr, void (*free_data)(void *));
// Resizes the array to a new size (internal use, but exposed)
void darray_armem_resize(darray_armem *arr, size_t new_size);
darray_armem darray_armem_slice(darray_armem *arr, size_t start, size_t end);
#endif // darray_armem_H

View File

@@ -0,0 +1,112 @@
#include "hashmap.h"
#include "../../../memory.h"
#include <gc/gc.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
struct hashmap_GC *createHashmap_GC() {
size_t size = 8;
struct hashmap_GC *t = (struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC));
t->size = size;
t->order = 1;
t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size);
memset(t->list, 0, sizeof(struct node_GC *) * size);
return t;
}
void resize_hashmap_GC(struct hashmap_GC *t) {
int old_size = t->size;
int new_size = old_size * 2;
struct node_GC **old_list = t->list;
// Create new list
t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * new_size);
memset(t->list, 0, sizeof(struct node_GC *) * new_size);
t->size = new_size;
t->count = 0;
// Rehash old entries into new list
for (int i = 0; i < old_size; i++) {
struct node_GC *temp = old_list[i];
while (temp) {
hashmap_insert_GC(t, temp->hash, temp->key, temp->val,
temp->order); // Will increment count
temp = temp->next;
}
}
}
int hashCode_GC(struct hashmap_GC *t, uint64_t hash) { return hash % t->size; }
int hashmap_remove_GC(struct hashmap_GC *t, uint64_t hash) {
int pos = hashCode_GC(t, hash);
struct node_GC *list = t->list[pos];
struct node_GC *temp = list;
struct node_GC *prev = NULL;
while (temp) {
if (temp->hash == hash) {
if (prev)
prev->next = temp->next;
else
t->list[pos] = temp->next;
return 1;
}
prev = temp;
temp = temp->next;
}
list = NULL;
prev = NULL;
temp = NULL;
return 0;
}
void hashmap_insert_GC(struct hashmap_GC *t, uint64_t hash, void *key,
void *val, size_t order) {
if (!order) {
order = t->order++;
}
if ((t->count + 1) > t->size * 0.75) {
resize_hashmap_GC(t);
}
int pos = hashCode_GC(t, hash);
struct node_GC *list = t->list[pos];
struct node_GC *temp = list;
// Check if key exists → overwrite
while (temp) {
if (temp->hash == hash) {
temp->val = val;
return;
}
temp = temp->next;
}
// Insert new node
struct node_GC *newNode = (struct node_GC *)ar_alloc(sizeof(struct node_GC));
newNode->hash = hash;
newNode->key = key;
newNode->val = val;
newNode->order = order;
newNode->next = list;
t->list[pos] = newNode;
t->count++;
}
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash) {
int pos = hashCode_GC(t, hash);
struct node_GC *list = t->list[pos];
struct node_GC *temp = list;
while (temp) {
if (temp->hash == hash) {
return temp->val;
}
temp = temp->next;
}
return NULL;
}

View File

@@ -0,0 +1,33 @@
#ifndef HASHMAP_GC_H
#define HASHMAP_GC_H
#include <stdint.h>
#include <stdlib.h>
typedef struct ArgonObject ArgonObject;
struct node_GC {
uint64_t hash;
void *key;
void *val;
size_t order;
struct node_GC *next;
};
struct hashmap_GC {
size_t size;
size_t count;
size_t order;
struct node_GC **list;
};
struct hashmap_GC *createHashmap_GC();
int hashCode_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 *val, size_t order);
void *hashmap_lookup_GC(struct hashmap_GC *t, uint64_t hash);
#endif // HASHMAP_GC_H

View File

@@ -2,7 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../memory.h"
#include "../../../memory.h"
LinkedList *create_list(size_t data_size) {
LinkedList *list = checked_malloc(sizeof(LinkedList));

View File

@@ -0,0 +1,40 @@
#include "../../runtime.h"
#include "../object.h"
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
ArgonObject *ARGON_FUNCTION_TYPE = NULL;
void init_function_type() {
ARGON_FUNCTION_TYPE = init_argon_class("Function");
}
void load_argon_function(Translated *translated, RuntimeState *state,
struct Stack stack) {
ArgonObject *object = init_child_argon_object(ARGON_FUNCTION_TYPE);
object->type = TYPE_FUNCTION;
uint64_t offset = pop_bytecode(translated, state);
uint64_t length = pop_bytecode(translated, state);
object->name = ar_alloc_atomic(length + 1);
memcpy(object->name, arena_get(&translated->constants, offset), length);
object->name[length] = '\0';
object->value.argon_fn.number_of_parameters = pop_bytecode(translated, state);
object->value.argon_fn.parameters =
ar_alloc(object->value.argon_fn.number_of_parameters * sizeof(char *));
for (size_t i = 0; i < object->value.argon_fn.number_of_parameters; i++) {
offset = pop_bytecode(translated, state);
length = pop_bytecode(translated, state);
object->value.argon_fn.parameters[i] = ar_alloc_atomic(length + 1);
memcpy(object->value.argon_fn.parameters[i], arena_get(&translated->constants, offset), length);
object->value.argon_fn.parameters[i][length] = '\0';
}
offset = pop_bytecode(translated, state);
length = pop_bytecode(translated, state);
darray_armem_init(&object->value.argon_fn.bytecode, sizeof(uint64_t));
darray_armem_resize(&object->value.argon_fn.bytecode, length/object->value.argon_fn.bytecode.element_size);
memcpy(object->value.argon_fn.bytecode.data, arena_get(&translated->constants, offset), length);
object->value.argon_fn.stack = stack;
state->registers[0]=object;
}

View File

@@ -0,0 +1,9 @@
#ifndef FUNCTION_H
#define FUNCTION_H
#include "../object.h"
void init_function_type();
ArgonObject *load_argon_function(Translated *translated, RuntimeState *state, struct Stack stack);
#endif // FUNCTION_H

View File

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

View File

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

View File

@@ -0,0 +1,37 @@
#include "object.h"
#include "../../hash_data/hash_data.h"
#include "../../memory.h"
#include "type/type.h"
#include <stdbool.h>
#include <string.h>
ArgonObject *BASE_CLASS = NULL;
void init_base_field() {
// add_field(BASE_CLASS, "test", BASE_CLASS);
}
ArgonObject *init_child_argon_object(ArgonObject *cls) {
ArgonObject *object = init_argon_class(NULL);
object->self = object;
object->baseObject = cls;
add_field(object, "__call__", NULL);
return object;
}
ArgonObject *init_argon_class(char *name) {
ArgonObject *object = ar_alloc(sizeof(ArgonObject));
object->name = name;
object->type = TYPE_OBJECT;
object->self = NULL;
object->baseObject = ARGON_TYPE;
object->fields = createHashmap_GC();
memset(&object->value, 0, sizeof(object->value));
return object;
}
void add_field(ArgonObject *target, char *name, ArgonObject *object) {
hashmap_insert_GC(target->fields,
siphash64_bytes(name, strlen(name), siphash_key), name,
object, 0);
}

View File

@@ -0,0 +1,53 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "../internals/hashmap/hashmap.h"
#include "../internals/dynamic_array_armem/darray_armem.h"
#include <gmp.h>
#include <stdbool.h>
#include "../runtime.h"
extern ArgonObject *BASE_CLASS;
struct string_struct {
char *data;
size_t length;
};
struct argon_function_struct {
darray_armem bytecode;
struct Stack stack;
size_t number_of_parameters;
char** parameters;
};
typedef enum {
TYPE_NULL,
TYPE_BOOL,
TYPE_NUMBER,
TYPE_STRING,
TYPE_FUNCTION,
TYPE_NATIVE_FUNCTION,
TYPE_OBJECT, // generic user object
} ArgonType;
struct ArgonObject {
ArgonType type;
char* name;
ArgonObject *self;
ArgonObject *baseObject;
struct hashmap_GC *fields; // dynamic fields/methods
union {
mpq_t as_number;
bool as_bool;
struct string_struct as_str;
void *native_fn;
struct argon_function_struct argon_fn;
// others as needed
} value;
};
typedef struct ArgonObject ArgonObject;
void init_base_field();
ArgonObject* init_child_argon_object(ArgonObject *cls);
ArgonObject* init_argon_class(char*name);
void add_field(ArgonObject*target, char* name, ArgonObject *object);
#endif // OBJECT_H

View File

@@ -0,0 +1,20 @@
#include "../object.h"
#include <stdint.h>
#include <stdio.h>
#include <stdio.h>
#include "string.h"
ArgonObject *ARGON_STRING_TYPE = NULL;
void init_string_type() {
ARGON_STRING_TYPE = init_argon_class("String");
}
ArgonObject *init_string_object(char*data, size_t length) {
ArgonObject * object = init_child_argon_object(ARGON_STRING_TYPE);
object->type = TYPE_STRING;
object->value.as_str.data = data;
object->value.as_str.length = length;
return object;
}

View File

@@ -0,0 +1,11 @@
#ifndef STRING_OBJ_H
#define STRING_OBJ_H
#include "../object.h"
extern ArgonObject *ARGON_STRING_TYPE;
void init_string_type();
ArgonObject *init_string_object(char*data, size_t length);
#endif // STRING_OBJ_H

View File

@@ -0,0 +1,11 @@
#include "../../internals/hashmap/hashmap.h"
#include "../object.h"
#include <string.h>
#include "type.h"
ArgonObject *ARGON_TYPE = NULL;
void init_type() {
ARGON_TYPE = init_argon_class("type");
ARGON_TYPE->baseObject = BASE_CLASS;
}

View File

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

91
src/runtime/runtime.c Normal file
View File

@@ -0,0 +1,91 @@
#include "runtime.h"
#include "../translator/translator.h"
#include "objects/functions/functions.h"
#include "objects/null/null.h"
#include "objects/object.h"
#include "objects/string/string.h"
#include "objects/type/type.h"
#include <fcntl.h>
#include <gc/gc.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
uint64_t bytes_to_uint64(const uint8_t bytes[8]) {
uint64_t value = 0;
for (int i = 0; i < 8; i++) {
value |= ((uint64_t)bytes[i]) << (i * 8);
}
return value;
}
void init_types() {
BASE_CLASS = init_argon_class("BASE_CLASS");
init_type();
init_function_type();
init_null();
init_string_type();
init_base_field();
}
uint8_t pop_byte(Translated *translated, RuntimeState *state) {
return *((uint8_t *)darray_get(&translated->bytecode, state->head++));
}
uint64_t pop_bytecode(Translated *translated, RuntimeState *state) {
uint8_t bytes[8];
for (size_t i = 0; i < sizeof(bytes); i++) {
bytes[i] = *((uint8_t *)darray_get(&translated->bytecode, state->head++));
}
return bytes_to_uint64(bytes);
}
void load_const(Translated *translated, RuntimeState *state) {
uint64_t to_register = pop_byte(translated, state);
types type = pop_byte(translated, state);
size_t length = pop_bytecode(translated, state);
uint64_t offset = pop_bytecode(translated, state);
void *data = ar_alloc_atomic(length);
memcpy(data, arena_get(&translated->constants, offset), length);
ArgonObject *object = ARGON_NULL;
switch (type) {
case TYPE_OP_STRING:
object = init_string_object(data, length);
break;
}
state->registers[to_register] = object;
}
void run_instruction(Translated *translated, RuntimeState *state,
struct Stack stack) {
OperationType opcode = pop_byte(translated, state);
switch (opcode) {
case OP_LOAD_NULL:
state->registers[pop_byte(translated, state)] = ARGON_NULL;
break;
case OP_LOAD_CONST:
load_const(translated, state);
break;
case OP_LOAD_FUNCTION:
load_argon_function(translated, state, stack);
break;
}
}
void runtime(Translated translated) {
RuntimeState state = {
checked_malloc(translated.registerCount * sizeof(ArgonObject *)), 0};
struct Stack stack = {};
state.head = 0;
while (state.head < translated.bytecode.size) {
run_instruction(&translated, &state, stack);
}
free(state.registers);
}

24
src/runtime/runtime.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef RUNTIME_H
#define RUNTIME_H
#include "../translator/translator.h"
#include "internals/hashmap/hashmap.h"
typedef struct {
ArgonObject **registers;
size_t head;
} RuntimeState;
typedef struct Stack {
ArgonObject *scope;
struct Stack *prev;
} Stack;
void init_types();
uint64_t pop_bytecode(Translated *translated, RuntimeState *state);
void run_instruction(Translated *translated, RuntimeState *state, struct Stack stack);
void runtime(Translated translated);
#endif // RUNTIME_H

View File

@@ -0,0 +1,45 @@
# Bytecode Specification
all opcodes are uint8_t, and all operands are uint64_t unless marked with an asterisk (*), where it is marked as uint8_t
## OP_LOAD_CONST
loads and initialises a value from the constant buffer into the provided register.
this operation 4 operands.
1. the register to write to. (*)
2. the type of data from the constant buffer. (*)
3. the length of the data in the constant buffer.
4. the offset in the constant buffer.
## OP_DECLARE
initilises a variable on the current scope with a given value. errors if the variable is already initilises on the current scope.
this operation takes 3 operands.
1. the length of the variable name.
2. the offset in the constant buffer of the variable name.
3. the register of the given value (*)
## OP_LOAD_NULL
sets a given register to null.
this operation takes 1 operand.
1. the register to set to null. (*)
## OP_LOAD_FUNCTION
initilises a function to a given register.
1. the offset of the name of the function.
2. the length of the name of the function.
3. the number of arguments.
4. the offset of the name of the argument.
5. the length of the name of the argument.
6. instruction 4 and 5 loop for each argument.
7. the offset of the bytecode of the function.
8. the length of the bytecode of the function.

View File

@@ -1,35 +1,30 @@
#include "../translator.h"
#include "declaration.h"
#include "../../parser/declaration/declaration.h"
#include "../translator.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
size_t translate_parsed_declaration(Translated *translated,
ParsedValue *parsedValue) {
DArray *delcarations = (DArray *)parsedValue->data;
set_registers(translated, 2);
DArray delcarations) {
set_registers(translated, 1);
size_t first = 0;
for (size_t i = 0; i < delcarations->size; i++) {
// TODO: add function delclaration
ParsedSingleDeclaration*singleDeclaration = darray_get(delcarations, i);
for (size_t i = 0; i < delcarations.size; i++) {
ParsedSingleDeclaration *singleDeclaration = darray_get(&delcarations, i);
size_t temp = translate_parsed(translated, singleDeclaration->from);
if (i==0) first = temp;
if (i == 0)
first = temp;
size_t length = strlen(singleDeclaration->name);
size_t offset = arena_push(&translated->constants, singleDeclaration->name, length);
size_t offset =
arena_push(&translated->constants, singleDeclaration->name, length);
push_instruction_code(translated, OP_LOAD_CONST);
push_instruction_code(translated, 1);
push_instruction_code(translated, TYPE_OP_STRING);
push_instruction_code(translated,length);
push_instruction_byte(translated, OP_DECLARE);
push_instruction_code(translated, length);
push_instruction_code(translated, offset);
push_instruction_code(translated, OP_DECLARE);
push_instruction_code(translated, 0);
push_instruction_code(translated, 1);
push_instruction_byte(translated, 0);
}
if (delcarations->size != 1) {
push_instruction_code(translated, OP_LOAD_NULL);
push_instruction_code(translated, 0);
if (delcarations.size != 1) {
push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_byte(translated, 0);
}
return first;
}

View File

@@ -2,9 +2,7 @@
#define BYTECODE_DECLARATION_H
#include "../translator.h"
size_t translate_parsed_string(Translated *translated, ParsedValue *parsedValue);
size_t translate_parsed_declaration(Translated *translated,
ParsedValue *parsedValue);
DArray delcarations);
#endif

View File

@@ -0,0 +1,37 @@
#include "function.h"
#include "../translator.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t translate_parsed_function(Translated *translated,
ParsedFunction *parsedFunction) {
DArray main_bytecode = translated->bytecode;
DArray _temp_bytecode;
darray_init(&_temp_bytecode, sizeof(uint8_t));
translated->bytecode = _temp_bytecode;
translate_parsed(translated, parsedFunction->body);
size_t function_bytecode_offset =
arena_push(&translated->constants, translated->bytecode.data,
translated->bytecode.size*translated->bytecode.element_size);
size_t function_bytecode_length = translated->bytecode.size;
darray_free(&translated->bytecode, NULL);
translated->bytecode = main_bytecode;
size_t start = push_instruction_byte(translated, OP_LOAD_FUNCTION);
size_t offset = arena_push(&translated->constants, parsedFunction->name,
strlen(parsedFunction->name));
push_instruction_code(translated, offset);
push_instruction_code(translated, strlen(parsedFunction->name));
push_instruction_code(translated, parsedFunction->parameters.size);
for (size_t i = 0; i < parsedFunction->parameters.size; i++) {
char **parameter_name = darray_get(&parsedFunction->parameters, i);
offset = arena_push(&translated->constants, *parameter_name,
strlen(*parameter_name));
push_instruction_code(translated, offset);
push_instruction_code(translated, strlen(*parameter_name));
}
push_instruction_code(translated, function_bytecode_offset);
push_instruction_code(translated, function_bytecode_length*translated->bytecode.element_size);
return start;
}

View File

@@ -0,0 +1,9 @@
#ifndef BYTECODE_FUNCTION_H
#define BYTECODE_FUNCTION_H
#include "../translator.h"
#include "../../parser/function/function.h"
size_t translate_parsed_function(Translated *translated,
ParsedFunction *parsedFunction);
#endif

View File

@@ -5,16 +5,15 @@
#include <stdio.h>
#include <string.h>
size_t translate_parsed_number(Translated *translated, ParsedValue *parsedValue) {
char *number_str = (char*)parsedValue->data;
size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register) {
size_t length = strlen(number_str);
size_t number_pos = arena_push(&translated->constants, number_str, length);
set_registers(translated, 1);
set_registers(translated, to_register+1);
size_t start = push_instruction_code(translated, OP_LOAD_CONST);
push_instruction_code(translated, 0);
size_t start = push_instruction_byte(translated, OP_LOAD_CONST);
push_instruction_byte(translated, to_register);
push_instruction_code(translated, TYPE_OP_NUMBER);
push_instruction_byte(translated, TYPE_OP_NUMBER);
push_instruction_code(translated,length);
push_instruction_code(translated, number_pos);
return start;

View File

@@ -2,6 +2,6 @@
#define BYTECODE_NUMBER_H
#include "../translator.h"
size_t translate_parsed_number(Translated *translated, ParsedValue *parsedValue);
size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register);
#endif

View File

@@ -1,18 +1,16 @@
#include "../translator.h"
#include "../../parser/string/string.h"
#include "string.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
size_t translate_parsed_string(Translated *translated, ParsedValue *parsedValue) {
ParsedString *parsedString = (ParsedString*)parsedValue->data;
size_t string_pos = arena_push(&translated->constants, parsedString->string, parsedString->length);
size_t translate_parsed_string(Translated *translated, ParsedString parsedString) {
size_t string_pos = arena_push(&translated->constants, parsedString.string, parsedString.length);
set_registers(translated, 1);
size_t start = push_instruction_code(translated, OP_LOAD_CONST);
push_instruction_code(translated, 0);
push_instruction_code(translated, TYPE_OP_STRING);
push_instruction_code(translated,parsedString->length);
size_t start = push_instruction_byte(translated, OP_LOAD_CONST);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, TYPE_OP_STRING);
push_instruction_code(translated,parsedString.length);
push_instruction_code(translated, string_pos);
return start;
}

View File

@@ -1,7 +1,8 @@
#ifndef BYTECODE_STRING_H
#define BYTECODE_STRING_H
#include "../translator.h"
#include "../../parser/string/string.h"
size_t translate_parsed_string(Translated *translated, ParsedValue *parsedValue);
size_t translate_parsed_string(Translated *translated, ParsedString parsedString);
#endif

View File

@@ -1,5 +1,8 @@
#include "translator.h"
#include "../hash_data/hash_data.h"
#include "../hashmap/hashmap.h"
#include "declaration/declaration.h"
#include "function/function.h"
#include "number/number.h"
#include "string/string.h"
#include <stddef.h>
@@ -8,10 +11,17 @@
#include <stdlib.h>
#include <string.h>
void uint64_to_bytes(uint64_t value, uint8_t bytes[8]) {
for (int i = 0; i < 8; i++) {
bytes[i] = (value >> (i * 8)) & 0xFF;
}
}
void arena_init(ConstantArena *arena) {
arena->data = checked_malloc(CHUNK_SIZE);
arena->capacity = CHUNK_SIZE;
arena->size = 0;
arena->hashmap = createHashmap();
}
void arena_resize(ConstantArena *arena, size_t new_size) {
@@ -31,6 +41,7 @@ void arena_free(ConstantArena *arena) {
free(arena->data);
arena->capacity = 0;
arena->size = 0;
hashmap_free(arena->hashmap, NULL);
}
void *arena_get(ConstantArena *arena, size_t offset) {
@@ -38,43 +49,57 @@ void *arena_get(ConstantArena *arena, size_t offset) {
}
size_t arena_push(ConstantArena *arena, const void *data, size_t length) {
if (arena->size >= length) {
for (size_t i = 0; i <= (arena->size - length); i++) {
if (memcmp(data, arena->data + i, length) == 0) {
return i;
}
uint64_t hash = siphash64_bytes(data, length, siphash_key);
// Look up offset in hashmap
void *val = hashmap_lookup(arena->hashmap, hash);
if (val != NULL) {
size_t offset =
(size_t)(uintptr_t)val - 1; // stored as pointer but really offset
// Verify to avoid collision false positive
if (memcmp(arena->data + offset, data, length) == 0) {
return offset;
}
}
// Not found: append data
arena_resize(arena, arena->size + length);
size_t offset = arena->size;
memcpy(arena->data + arena->size, data, length);
arena->size += length;
// Insert into hashmap: store offset as pointer-sized integer
hashmap_insert(arena->hashmap, hash, (void *)data,
(void *)(uintptr_t)offset + 1, 0);
return offset;
}
Translated init_translator() {
Translated translated;
translated.registerCount = 0;
darray_init(&translated.bytecode, sizeof(uint64_t));
darray_init(&translated.bytecode, sizeof(uint8_t));
arena_init(&translated.constants);
return translated;
}
void set_instruction_code(Translated *translator, size_t offset,
uint64_t code) {
code = htole64(code);
size_t *ptr = (translator->bytecode.data + offset);
*ptr = code;
}
size_t push_instruction_code(Translated *translator, uint64_t code) {
code = htole64(code);
size_t push_instruction_byte(Translated *translator, uint8_t byte) {
size_t offset = translator->bytecode.size;
darray_push(&translator->bytecode, &code);
darray_push(&translator->bytecode, &byte);
return offset;
}
void set_registers(Translated *translator, size_t count) {
size_t push_instruction_code(Translated *translator, uint64_t code) {
size_t offset = translator->bytecode.size;
uint8_t bytes[8];
uint64_to_bytes(code, bytes);
for (size_t i = 0; i < sizeof(bytes); i++) {
darray_push(&translator->bytecode, &(bytes[i]));
}
return offset;
}
void set_registers(Translated *translator, uint8_t count) {
if (count > translator->registerCount)
translator->registerCount = count;
}
@@ -82,16 +107,21 @@ void set_registers(Translated *translator, size_t count) {
size_t translate_parsed(Translated *translated, ParsedValue *parsedValue) {
switch (parsedValue->type) {
case AST_STRING:
return translate_parsed_string(translated, parsedValue);
return translate_parsed_string(translated,
*((ParsedString *)parsedValue->data));
case AST_DECLARATION:
return translate_parsed_declaration(translated, parsedValue);
return translate_parsed_declaration(translated,
*((DArray *)parsedValue->data));
case AST_NUMBER:
return translate_parsed_number(translated, parsedValue);
return translate_parsed_number(translated, (char *)parsedValue->data, 0);
case AST_NULL:
set_registers(translated, 1);
size_t output = push_instruction_code(translated, OP_LOAD_NULL);
push_instruction_code(translated, 0);
size_t output = push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_byte(translated, 0);
return output;
case AST_FUNCTION:
return translate_parsed_function(translated,
(ParsedFunction *)parsedValue->data);
}
return 0;
}

View File

@@ -4,33 +4,37 @@
#include "../dynamic_array/darray.h"
#include "../memory.h"
#include "../parser/parser.h"
#include "../hashmap/hashmap.h"
#include <stddef.h>
#include <stdint.h>
typedef enum { OP_LOAD_CONST = 255, OP_DECLARE, OP_LOAD_NULL, OP_JUMP } OperationType;
typedef enum { TYPE_OP_STRING = 255, TYPE_OP_NUMBER } types;
typedef enum { OP_LOAD_CONST, OP_DECLARE, OP_LOAD_NULL, OP_LOAD_FUNCTION } OperationType;
typedef enum { TYPE_OP_STRING, TYPE_OP_NUMBER } types;
typedef struct {
void *data;
size_t capacity;
size_t size;
struct hashmap * hashmap;
} ConstantArena;
typedef struct {
size_t registerCount;
uint8_t registerCount;
DArray bytecode;
ConstantArena constants;
} Translated;
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);
void set_instruction_code(Translated * translator, size_t offset, uint64_t code);
size_t push_instruction_byte(Translated *translator, uint8_t byte);
size_t push_instruction_code(Translated *translator, uint64_t code);
void set_registers(Translated *translator, size_t count);
void set_registers(Translated *translator, uint8_t count);
Translated init_translator();

14
test.ar
View File

@@ -1,3 +1,12 @@
"h"
"e"
"ll"
"o"
" "
"wo"
"rl"
"d"
"world"
"hello world"
"hello world"
"hello world"
@@ -15,7 +24,10 @@
"hello world"
"hello\u0000world"
"🇬🇧"
"hello\u0000world"
"\u0000"
"hello"
let hello = "helllo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbruhhhhh"
1.24323234e2312324

View File

@@ -1 +0,0 @@
"\u0000"