Compare commits

..

7 Commits

Author SHA1 Message Date
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
26 changed files with 635 additions and 116 deletions

2
null_test.ar Normal file
View File

@@ -0,0 +1,2 @@
null
"hello\u0000world"

View File

@@ -1,83 +0,0 @@
#include "hashmap.h"
#include <stdlib.h>
#include "../memory.h"
struct table *createTable(int size)
{
struct table *t = (struct table *)checked_malloc(sizeof(struct table));
t->size = size;
t->list = (struct node **)checked_malloc(sizeof(struct node *) * size);
int i;
for (i = 0; i < size; i++)
t->list[i] = NULL;
return t;
}
int hashCode(struct table *t, int key)
{
if (key < 0)
return -(key % t->size);
return key % t->size;
}
int remove(struct table *t, int key)
{
int pos = hashCode(t, key);
struct node *list = t->list[pos];
struct node *temp = list;
struct node *prev = NULL;
while (temp)
{
if (temp->key == key)
{
if (prev)
prev->next = temp->next;
else
t->list[pos] = temp->next;
free(temp);
return 1;
}
prev = temp;
temp = temp->next;
}
return 0;
}
void insert(struct table *t, int key, void* val)
{
int pos = hashCode(t, key);
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)
{
temp->val = val;
return;
}
temp = temp->next;
}
newNode->key = key;
newNode->val = val;
newNode->next = list;
t->list[pos] = newNode;
}
void *lookup(struct table *t, int key)
{
int pos = hashCode(t, key);
struct node *list = t->list[pos];
struct node *temp = list;
while (temp)
{
if (temp->key == key)
{
return temp->val;
}
temp = temp->next;
}
return NULL;
}

View File

@@ -1,24 +0,0 @@
#ifndef HASHMAP_H
#define HASHMAP_H
struct node
{
int key;
void *val;
struct node *next;
};
struct table
{
int size;
struct node **list;
};
struct table *createTable(int size);
int hashCode(struct table *t, int key);
int remove(struct table *t, int key);
void insert(struct table *t, int key, void* val);
#endif // HASHMAP_H

View File

@@ -4,6 +4,7 @@
#include "memory.h" #include "memory.h"
#include "parser/parser.h" #include "parser/parser.h"
#include "translator/translator.h" #include "translator/translator.h"
#include "runtime/runtime.h"
#include <endian.h> #include <endian.h>
#include <string.h> #include <string.h>
@@ -73,6 +74,12 @@ int main(int argc, char *argv[]) {
fclose(file); fclose(file);
generate_siphash_key();
init_types();
runtime(translated);
free_translator(&translated); free_translator(&translated);
return 0; return 0;
} }

View File

@@ -6,6 +6,9 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
// runtime
#include "runtime/objects/type/type.h"
void *checked_malloc(size_t size) { void *checked_malloc(size_t size) {
void *ptr = malloc(size); void *ptr = malloc(size);
if (!ptr) { if (!ptr) {

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 *createHashmap() {
size_t size = 8;
struct hashmap *t = (struct hashmap *)ar_alloc(sizeof(struct hashmap));
t->size = size;
t->order = 1;
t->list = (struct node **)ar_alloc(sizeof(struct node *) * size);
memset(t->list, 0, sizeof(struct node *) * size);
return t;
}
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 **)ar_alloc(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;
}
}
}
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->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(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 *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 *newNode = (struct node *)ar_alloc(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 *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->hash == hash) {
return temp->val;
}
temp = temp->next;
}
return NULL;
}

View File

@@ -0,0 +1,33 @@
#ifndef HASHMAP_H
#define HASHMAP_H
#include <stdint.h>
#include <stdlib.h>
typedef struct ArgonObject ArgonObject;
struct node {
uint64_t hash;
void *key;
void *val;
size_t order;
struct node *next;
};
struct hashmap {
size_t size;
size_t count;
size_t order;
struct node **list;
};
struct hashmap *createHashmap();
int hashCode(struct hashmap *t, uint64_t hash);
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

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

View File

@@ -0,0 +1,185 @@
/*
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/>.
*/
#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,22 @@
/*
SipHash reference C implementation
Copyright (c) 2012-2021 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/>.
*/
#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

@@ -0,0 +1,10 @@
#include "../../internals/hashmap/hashmap.h"
#include "../object.h"
#include <string.h>
#include "null.h"
ArgonObject *ARGON_NULL = NULL;
void init_null() {
ARGON_NULL = init_argon_object();
}

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,24 @@
#include "object.h"
#include "../../memory.h"
#include "../runtime.h"
#include <string.h>
ArgonObject *BASE_OBJECT = NULL;
void init_base_field() {
add_field(BASE_OBJECT, "test", BASE_OBJECT);
}
ArgonObject* init_argon_object() {
ArgonObject *object = ar_alloc(sizeof(ArgonObject));
object->type = TYPE_OBJECT;
object->typeObject = NULL;
object->baseObject = BASE_OBJECT;
object->fields = createHashmap();
memset(&object->value, 0, sizeof(object->value));
return object;
}
void add_field(ArgonObject*target, char* name, ArgonObject *object) {
hashmap_insert(target->fields, siphash64_bytes(name, strlen(name)),name, object, 0);
}

View File

@@ -0,0 +1,43 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "../internals/hashmap/hashmap.h"
#include <gmp.h>
#include <stdbool.h>
extern ArgonObject *BASE_OBJECT;
struct string_struct {
char *data;
size_t length;
};
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;
ArgonObject *baseObject;
ArgonObject *typeObject;
struct hashmap *fields; // dynamic fields/methods
union {
mpq_t as_number;
bool as_bool;
struct string_struct as_str;
void *native_fn;
// others as needed
} value;
};
typedef struct ArgonObject ArgonObject;
void init_base_field();
ArgonObject *init_argon_object();
void add_field(ArgonObject*target, char* name, ArgonObject *object);
#endif // OBJECT_H

View File

@@ -0,0 +1,25 @@
#include "../object.h"
#include <stdint.h>
#include <stdio.h>
#include <stdio.h>
ArgonObject *ARGON_STRING_TYPE = NULL;
ArgonObject *ARGON_STRING_BASE = NULL;
void init_string_type() {
ARGON_STRING_TYPE = init_argon_object();
ARGON_STRING_BASE = init_argon_object();
}
ArgonObject *init_string_object(char*data, size_t length) {
fwrite(data, 1, length, stdout);
printf("\n");
ArgonObject * object = init_argon_object();
object->typeObject = ARGON_STRING_TYPE;
object->baseObject = ARGON_STRING_BASE;
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,10 @@
#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_object();
}

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

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

@@ -0,0 +1,88 @@
#include "runtime.h"
#include "../translator/translator.h"
#include "internals/siphash/siphash.h"
#include "objects/null/null.h"
#include "objects/object.h"
#include "objects/string/string.h"
#include "objects/type/type.h"
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void init_types() {
BASE_OBJECT = init_argon_object();
init_type();
init_null();
init_string_type();
init_base_field();
}
uint64_t pop_bytecode(Translated *translated, RuntimeState *state) {
uint64_t *instruction = darray_get(&translated->bytecode, state->head++);
return *instruction;
}
void load_const(Translated *translated, RuntimeState *state) {
uint64_t to_register = pop_bytecode(translated, state);
types type = pop_bytecode(translated, state);
size_t length = pop_bytecode(translated, state);
uint64_t offset = pop_bytecode(translated, state);
void*data = ar_alloc(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) {
OperationType opcode = pop_bytecode(translated, state);
switch (opcode) {
case OP_LOAD_NULL:
state->registers[pop_bytecode(translated, state)] = ARGON_NULL;
break;
case OP_LOAD_CONST:
load_const(translated,state);
break;
}
}
void runtime(Translated translated) {
RuntimeState state = {
checked_malloc(translated.registerCount * sizeof(ArgonObject *)), 0};
while (state.head < translated.bytecode.size)
run_instruction(&translated, &state);
free(state.registers);
}
static uint8_t siphash_key[16];
void generate_siphash_key() {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0 || read(fd, siphash_key, 16) != 16) {
// Fallback or abort
}
close(fd);
}
uint64_t siphash64_bytes(const void *data, size_t len) {
uint8_t out[8];
if (siphash(data, len, siphash_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;
}

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

@@ -0,0 +1,21 @@
#ifndef RUNTIME_H
#define RUNTIME_H
#include "../translator/translator.h"
#include "internals/hashmap/hashmap.h"
typedef struct {
ArgonObject **registers;
size_t head;
} RuntimeState;
void init_types();
void run_instruction(Translated *translated, RuntimeState *state);
void runtime(Translated translated);
uint64_t siphash64_bytes(const void *data, size_t len);
void generate_siphash_key();
#endif // RUNTIME_H

View File

@@ -4,11 +4,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
size_t translate_parsed_string(Translated *translated, ParsedString parsedString, size_t to_register) { size_t translate_parsed_string(Translated *translated, ParsedString parsedString) {
size_t string_pos = arena_push(&translated->constants, parsedString.string, parsedString.length); size_t string_pos = arena_push(&translated->constants, parsedString.string, parsedString.length);
set_registers(translated, to_register+1); set_registers(translated, 1);
size_t start = push_instruction_code(translated, OP_LOAD_CONST); size_t start = push_instruction_code(translated, OP_LOAD_CONST);
push_instruction_code(translated, to_register); push_instruction_code(translated, 0);
push_instruction_code(translated, TYPE_OP_STRING); push_instruction_code(translated, TYPE_OP_STRING);
push_instruction_code(translated,parsedString.length); push_instruction_code(translated,parsedString.length);
push_instruction_code(translated, string_pos); push_instruction_code(translated, string_pos);

View File

@@ -3,6 +3,6 @@
#include "../translator.h" #include "../translator.h"
#include "../../parser/string/string.h" #include "../../parser/string/string.h"
size_t translate_parsed_string(Translated *translated, ParsedString parsedString, size_t to_register); size_t translate_parsed_string(Translated *translated, ParsedString parsedString);
#endif #endif

View File

@@ -62,7 +62,6 @@ Translated init_translator() {
void set_instruction_code(Translated *translator, size_t offset, void set_instruction_code(Translated *translator, size_t offset,
uint64_t code) { uint64_t code) {
code = htole64(code);
size_t *ptr = (translator->bytecode.data + offset); size_t *ptr = (translator->bytecode.data + offset);
*ptr = code; *ptr = code;
} }
@@ -82,7 +81,7 @@ void set_registers(Translated *translator, size_t count) {
size_t translate_parsed(Translated *translated, ParsedValue *parsedValue) { size_t translate_parsed(Translated *translated, ParsedValue *parsedValue) {
switch (parsedValue->type) { switch (parsedValue->type) {
case AST_STRING: case AST_STRING:
return translate_parsed_string(translated, *((ParsedString*)parsedValue->data), 0); return translate_parsed_string(translated, *((ParsedString*)parsedValue->data));
case AST_DECLARATION: case AST_DECLARATION:
return translate_parsed_declaration(translated, *((DArray*)parsedValue->data)); return translate_parsed_declaration(translated, *((DArray*)parsedValue->data));
case AST_NUMBER: case AST_NUMBER:

14
test.ar
View File

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

View File

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