Compare commits

...

33 Commits

Author SHA1 Message Date
fe7eaa8de3 fix some memory leaks 2025-07-09 14:47:16 +01:00
66b44e8f3a add full return err support in parser 2025-07-09 14:34:00 +01:00
0cb55fc563 move assign to return errors 2025-07-09 05:09:12 +01:00
c4731597f3 start rewriting the parser to return with error messages so errors can be caught 2025-07-09 04:58:49 +01:00
e234ea074b start adding error message support 2025-07-09 01:55:40 +01:00
9e5e932d39 start adding error message support 2025-07-09 01:55:32 +01:00
fba074a5a4 limit arguments to not support duplicate names 2025-07-08 04:31:01 +01:00
72cc87f5b6 create executable function which identifies and loads a cache if available 2025-07-07 04:03:11 +01:00
5c0ced5e45 start supporting identifiers in bytecode 2025-07-06 03:19:30 +01:00
886599c9c5 change to use cwalk for paths 2025-07-05 23:56:54 +01:00
cbebe4812b pull submodules 2025-07-05 04:58:08 +01:00
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
93 changed files with 2570 additions and 444 deletions

View File

@@ -12,6 +12,8 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Python (needed for Conan) - name: Setup Python (needed for Conan)
uses: actions/setup-python@v4 uses: actions/setup-python@v4

2
.gitignore vendored
View File

@@ -60,4 +60,4 @@ build
*.yy.c *.yy.c
*.yy.h *.yy.h
out.arbin __arcache__

9
.gitmodules vendored Normal file
View File

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

View File

@@ -30,7 +30,10 @@ add_custom_command(
add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H}) add_custom_target(GenerateLexer DEPENDS ${LEXER_C} ${LEXER_H})
# Step 3: Add executable # Step 3: Add executable
add_executable(argon ${CFILES} ${LEXER_C}) add_executable(argon external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c ${CFILES} ${LEXER_C})
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
target_include_directories(argon PRIVATE ${CMAKE_SOURCE_DIR}/external/cwalk/include)
target_include_directories(argon PRIVATE ${CMAKE_SOURCE_DIR}/external/libdye/include)
# Step 4: Build order # Step 4: Build order
add_dependencies(argon GenerateLexer) add_dependencies(argon GenerateLexer)
@@ -56,3 +59,5 @@ target_link_libraries(argon PRIVATE
target_include_directories(argon PRIVATE target_include_directories(argon PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/lexer ${CMAKE_CURRENT_SOURCE_DIR}/src/lexer
) )
add_custom_command(TARGET argon POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:argon>)

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 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007

View File

@@ -2,8 +2,8 @@ LEXER_SRC = src/lexer/lex.l
LEXER_C = src/lexer/lex.yy.c LEXER_C = src/lexer/lex.yy.c
LEXER_H = src/lexer/lex.yy.h LEXER_H = src/lexer/lex.yy.h
CFILES = $(shell find src -name '*.c') CFILES = external/xxhash/xxhash.c external/cwalk/src/cwalk.c external/libdye/src/dye.c $(shell find src -name '*.c')
CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function CFLAGS = $(ARCHFLAGS) -lm -lgc -lgmp -Wall -Wextra -Wno-unused-function -Iexternal/cwalk/include -Iexternal/libdye/include
BINARY = bin/argon BINARY = bin/argon
all: $(BINARY) all: $(BINARY)
@@ -15,6 +15,10 @@ $(BINARY): $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -O3 -o $(BINARY) $(CFILES) $(CFLAGS) -s gcc -O3 -o $(BINARY) $(CFILES) $(CFLAGS) -s
native: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin
gcc -O3 -march=native -o $(BINARY) $(CFILES) $(CFLAGS)
debug: $(CFILES) $(LEXER_C) $(LEXER_H) debug: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -g -O0 -o $(BINARY) $(CFILES) $(CFLAGS) gcc -g -O0 -o $(BINARY) $(CFILES) $(CFLAGS)
@@ -26,7 +30,7 @@ full-debug: $(CFILES) $(LEXER_C) $(LEXER_H)
optimised: $(CFILES) $(LEXER_C) $(LEXER_H) optimised: $(CFILES) $(LEXER_C) $(LEXER_H)
mkdir -p bin mkdir -p bin
gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS) gcc -O3 -fprofile-generate -o $(BINARY) $(CFILES) $(CFLAGS)
${BINARY} test.ar ${BINARY} rand_test.ar
gcc -O3 -fprofile-use -o $(BINARY) $(CFILES) $(CFLAGS) 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/cwalk vendored Submodule

Submodule external/cwalk added at e98d23f688

1
external/libdye vendored Submodule

Submodule external/libdye added at c3fa048e65

1
external/xxhash vendored Submodule

Submodule external/xxhash added at 38d555879f

7
gentest.py Normal file
View File

@@ -0,0 +1,7 @@
import random
import sys
for i in range(100000000):
sys.stdout.write("\"")
sys.stdout.write(str(random.random()))
sys.stdout.write("\"\n")

52
src/arobject.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef AROBJECT_H
#define AROBJECT_H
#include <gmp.h>
#include "runtime/internals/dynamic_array_armem/darray_armem.h"
typedef struct ArgonObject ArgonObject; // forward declaration
typedef enum ArgonType {
TYPE_NULL,
TYPE_BOOL,
TYPE_NUMBER,
TYPE_STRING,
TYPE_FUNCTION,
TYPE_NATIVE_FUNCTION,
TYPE_OBJECT,
} ArgonType;
struct string_struct {
char *data;
size_t length;
};
typedef struct Stack {
ArgonObject *scope;
struct Stack *prev;
} Stack;
struct argon_function_struct {
darray_armem bytecode;
Stack stack;
size_t number_of_parameters;
char **parameters;
};
// full definition of ArgonObject (no typedef again!)
struct ArgonObject {
ArgonType type;
char *name;
ArgonObject *self;
ArgonObject *baseObject;
struct hashmap_GC *fields;
union {
mpq_t as_number;
bool as_bool;
struct string_struct as_str;
void *native_fn;
struct argon_function_struct argon_fn;
} value;
};
#endif // AROBJECT_H

View File

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

134
src/err.c Normal file
View File

@@ -0,0 +1,134 @@
#include "err.h"
#include "../external/libdye/include/dye.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const ArErr no_err = (ArErr){false};
ArErr create_err(int64_t line, int64_t column, int length, char *path,
const char *type, const char *fmt, ...) {
ArErr err;
err.exists = true;
err.path = path;
err.line = line;
err.column = column;
err.length = length;
// Copy error type safely
strncpy(err.type, type, sizeof(err.type) - 1);
err.type[sizeof(err.type) - 1] = '\0';
// Format error message
va_list args;
va_start(args, fmt);
vsnprintf(err.message, sizeof(err.message), fmt, args);
va_end(args);
return err;
}
void output_err(ArErr err) {
if (!err.exists)
return;
dye(stderr, DYE_WHITE, DYE_RED);
fprintf(stderr, "ERROR!");
dye(stderr, DYE_RESET, DYE_RESET);
fprintf(stderr, " ");
dyefg(stderr, DYE_RED);
dye_style(stderr, DYE_STYLE_BOLD);
fprintf(stderr, "%s", err.type);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, ": ");
dyefg(stderr, DYE_RED);
fprintf(stderr, "%s", err.message);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "\n");
if (err.path && err.line) {
dyefg(stderr, DYE_GRAY);
fprintf(stderr, " --> ");
dyefg(stderr, DYE_CYAN);
fprintf(stderr, "%s", err.path);
dyefg(stderr, DYE_GRAY);
fprintf(stderr, ":");
dyefg(stderr, DYE_YELLOW);
fprintf(stderr, "%zu", err.line);
dyefg(stderr, DYE_GRAY);
fprintf(stderr, ":");
dyefg(stderr, DYE_YELLOW);
fprintf(stderr, "%zu", err.column);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "\n");
FILE *file = fopen(err.path, "r");
if (file) {
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
int line_number_width = snprintf(NULL, 0, "%zu", err.line);
char *buffer = NULL;
size_t size = 0;
int current_line = 1;
ssize_t len;
while ((len = getline(&buffer, &size, file)) != -1) {
if (current_line == err.line) {
break;
}
current_line++;
}
fprintf(stderr, " ");
for (int i = 0; i < line_number_width; i++) {
fprintf(stderr, " ");
}
fprintf(stderr, "|\n");
getline(&buffer, &size, file);
char *line_starts = buffer;
while (*line_starts && isspace((unsigned char)*line_starts) && line_starts-buffer < err.column-1) {
line_starts++;
err.column--;
}
fprintf(stderr, " %zu | ", err.line);
if (err.length) {
fprintf(stderr, "%.*s", (int)err.column-1, line_starts);
dyefg(stderr, DYE_RED);
dye_style(stderr, DYE_STYLE_BOLD);
fprintf(stderr, "%.*s", err.length, line_starts + err.column - 1);
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "%s", line_starts + (int)err.column + err.length - 1);
for (int64_t i = 0; i < err.column - 1; i++) {
fprintf(stderr, " ");
}
} else {
fprintf(stderr, "%s", line_starts);
}
free(buffer);
fprintf(stderr, "\n ");
for (int i = 0; i < line_number_width; i++) {
fprintf(stderr, " ");
}
fprintf(stderr, "| ");
for (int i = 1; i < err.column; i++) {
fprintf(stderr, " ");
}
dyefg(stderr, DYE_RED);
dye_style(stderr, DYE_STYLE_BOLD);
for (int i = 0; i < err.length; i++) {
fprintf(stderr, "^");
}
dye_style(stderr, DYE_STYLE_RESET);
dyefg(stderr, DYE_RESET);
fprintf(stderr, "\n");
}
}
}

7
src/err.h Normal file
View File

@@ -0,0 +1,7 @@
#include "returnTypes.h"
extern const ArErr no_err;
ArErr create_err(int64_t line, int64_t column, int length, char *path, const char *type,
const char *fmt, ...);
void output_err(ArErr err);

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

View File

@@ -1,24 +1,35 @@
#ifndef HASHMAP_H #ifndef HASHMAP_H
#define HASHMAP_H #define HASHMAP_H
#include <stdint.h>
#include <stdlib.h>
struct node typedef void (*free_val_func)(void *val);
{
int key; struct node {
uint64_t hash;
void *key;
void *val; void *val;
size_t order;
struct node *next; struct node *next;
}; };
struct table struct hashmap {
{ size_t size;
int size; size_t count;
size_t order;
struct node **list; 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 #endif // HASHMAP_H

View File

@@ -108,8 +108,6 @@ int yywrap(void * unused_param) {
#[^\n]* { /* skip comment */ } #[^\n]* { /* skip comment */ }
. { . {
GET_STATE return TOKEN_INVALID;
fprintf(stderr, "%s:%zu:%zu error: unexpected character '%s'\n", state->path, state->current_line+1, COLUMN_NO+1, yytext);
exit(1);
} }
%% %%

View File

@@ -1,8 +1,8 @@
#include "lexer.h" #include "lexer.h"
#include "lex.yy.h"
#include "../string/string.h" #include "../string/string.h"
#include "lex.yy.h"
void lexer(LexerState state) { ArErr lexer(LexerState state) {
size_t line = 1; size_t line = 1;
size_t column = 1; size_t column = 1;
int ch; int ch;
@@ -32,13 +32,16 @@ void lexer(LexerState state) {
int token; int token;
while ((token = yylex(scanner)) != 0) { while ((token = yylex(scanner)) != 0) {
Token token_struct = (Token){ if (token == TOKEN_INVALID) {
token, ArErr err = create_err(state.current_line + 1, state.current_column + 1,
state.current_line+1, yyget_leng(scanner), state.path, "Syntax Error",
state.current_column+1, "Invalid Token '%s'", yyget_text(scanner));
yyget_leng(scanner), yylex_destroy(scanner);
cloneString(yyget_text(scanner)) return err;
}; }
Token token_struct =
(Token){token, state.current_line + 1, state.current_column + 1,
yyget_leng(scanner), cloneString(yyget_text(scanner))};
darray_push(state.tokens, &token_struct); darray_push(state.tokens, &token_struct);
if (token == TOKEN_NEW_LINE) { if (token == TOKEN_NEW_LINE) {
state.current_line += 1; state.current_line += 1;
@@ -48,4 +51,5 @@ void lexer(LexerState state) {
} }
} }
yylex_destroy(scanner); yylex_destroy(scanner);
return no_err;
} }

View File

@@ -4,9 +4,10 @@
#include "../dynamic_array/darray.h" #include "../dynamic_array/darray.h"
#include "token.h" #include "token.h"
#include <stdio.h> #include <stdio.h>
#include "../err.h"
typedef struct { typedef struct {
const char *path; char *path;
FILE *file; FILE *file;
size_t current_line; size_t current_line;
size_t current_column; size_t current_column;
@@ -14,6 +15,6 @@ typedef struct {
// add more fields as needed // add more fields as needed
} LexerState; } LexerState;
void lexer(LexerState state); ArErr lexer(LexerState state);
#endif // LEXER_H #endif // LEXER_H

View File

@@ -72,6 +72,7 @@ typedef enum {
TOKEN_COMMA, TOKEN_COMMA,
TOKEN_COLON, TOKEN_COLON,
TOKEN_EXCLAMATION, TOKEN_EXCLAMATION,
TOKEN_INVALID,
} TokenType; } TokenType;
typedef struct { typedef struct {

View File

@@ -3,68 +3,281 @@
#include "lexer/token.h" #include "lexer/token.h"
#include "memory.h" #include "memory.h"
#include "parser/parser.h" #include "parser/parser.h"
#include "runtime/runtime.h"
#include "translator/translator.h" #include "translator/translator.h"
#include "../external/xxhash/xxhash.h"
#include "hash_data/hash_data.h"
#include <arpa/inet.h>
#include <endian.h> #include <endian.h>
#include <string.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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.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 "../external/cwalk/include/cwalk.h"
#include <string.h>
const char FILE_IDENTIFIER[] = "ARBI"; #ifdef _WIN32
const uint64_t version_number = 0; #include <windows.h>
#else
#include <limits.h>
#include <unistd.h>
#endif
#include "err.h"
int main(int argc, char *argv[]) { char *get_current_directory() {
setlocale(LC_ALL, ""); char *buffer = NULL;
if (argc <= 1)
return -1;
ar_memory_init();
char *path = argv[1];
DArray tokens;
darray_init(&tokens, sizeof(Token)); #ifdef _WIN32
DWORD size = GetCurrentDirectoryA(0, NULL);
buffer = malloc(size);
if (buffer == NULL)
return NULL;
if (GetCurrentDirectoryA(size, buffer) == 0) {
free(buffer);
return NULL;
}
#else
long size = pathconf(".", _PC_PATH_MAX);
if (size == -1)
size = 4096; // fallback
buffer = malloc(size);
if (buffer == NULL)
return NULL;
if (getcwd(buffer, size) == NULL) {
free(buffer);
return NULL;
}
#endif
FILE *file = fopen(path, "r"); return buffer;
if (!file) {
return -1;
} }
LexerState state = {path, file, 0, 0, &tokens}; int ensure_dir_exists(const char *path) {
lexer(state); 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;
}
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) {
FILE *bytecode_file = fopen(joined_paths, "rb");
if (!bytecode_file)
return 1;
char file_identifier_from_cache[sizeof(FILE_IDENTIFIER)] = {0};
if (fread(&file_identifier_from_cache, 1,
sizeof(file_identifier_from_cache) - 1,
bytecode_file) != sizeof(file_identifier_from_cache) - 1 ||
memcmp(file_identifier_from_cache, FILE_IDENTIFIER,
sizeof(file_identifier_from_cache)) != 0) {
goto FAILED;
}
uint32_t read_version;
if (fread(&read_version, 1, sizeof(read_version), bytecode_file) !=
sizeof(read_version)) {
goto FAILED;
}
read_version = le32toh(read_version);
if (read_version != version_number) {
goto FAILED;
}
uint64_t read_hash;
if (fread(&read_hash, 1, sizeof(read_hash), bytecode_file) !=
sizeof(read_hash)) {
goto FAILED;
}
read_hash = le64toh(read_hash);
if (read_hash != hash) {
goto FAILED;
}
uint8_t register_count;
if (fread(&register_count, 1, sizeof(register_count), bytecode_file) !=
sizeof(register_count)) {
goto FAILED;
}
uint64_t constantsSize;
if (fread(&constantsSize, 1, sizeof(constantsSize), bytecode_file) !=
sizeof(constantsSize)) {
goto FAILED;
}
constantsSize = le64toh(constantsSize);
uint64_t bytecodeSize;
if (fread(&bytecodeSize, 1, sizeof(bytecodeSize), bytecode_file) !=
sizeof(bytecodeSize)) {
goto FAILED;
}
bytecodeSize = le64toh(bytecodeSize);
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;
}
Execution execute(char *absolute_path) {
clock_t start, end;
double time_spent, total_time_spent = 0;
const char *basename_ptr;
size_t basename_length;
cwk_path_get_basename(absolute_path, &basename_ptr, &basename_length);
if (!basename_ptr)
return (Execution){create_err(0, 0, 0, NULL, "Path Error",
"path has no basename '%s'", absolute_path),
(Stack){NULL, NULL}};
char basename[FILENAME_MAX];
memcpy(basename, basename_ptr, basename_length);
size_t parent_directory_length;
cwk_path_get_dirname(absolute_path, &parent_directory_length);
char parent_directory[FILENAME_MAX];
memcpy(parent_directory, absolute_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(absolute_path, "r");
if (!file) {
return (Execution){create_err(0, 0, 0, NULL, "File Error",
"Unable to open file '%s'", absolute_path),
(Stack){NULL, NULL}};
}
XXH3_state_t *hash_state = XXH3_createState();
XXH3_64bits_reset(hash_state);
char buffer[8192];
size_t bytes;
while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) {
XXH3_64bits_update(hash_state, buffer, bytes);
}
rewind(file);
uint64_t hash = XXH3_64bits_digest(hash_state);
XXH3_freeState(hash_state);
Translated translated = init_translator();
if (load_cache(&translated, cache_file_path, hash) != 0) {
free_translator(&translated);
translated = init_translator();
DArray tokens;
darray_init(&tokens, sizeof(Token));
LexerState state = {absolute_path, file, 0, 0, &tokens};
start = clock();
ArErr err = lexer(state);
if (err.exists) {
free_translator(&translated);
darray_free(&tokens, free_token);
return (Execution){err, (Stack){NULL, NULL}};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Lexer time taken: %f seconds\n", time_spent);
fclose(state.file); fclose(state.file);
DArray ast; DArray ast;
darray_init(&ast, sizeof(ParsedValue)); darray_init(&ast, sizeof(ParsedValue));
parser(path, &ast, &tokens, false); start = clock();
err = parser(absolute_path, &ast, &tokens, false);
if (err.exists) {
free_translator(&translated);
darray_free(&tokens, free_token);
darray_free(&ast, free_parsed);
return (Execution){err, (Stack){NULL, NULL}};
}
end = clock();
time_spent = (double)(end - start) / CLOCKS_PER_SEC;
total_time_spent += time_spent;
printf("Parser time taken: %f seconds\n", time_spent);
darray_free(&tokens, free_token); darray_free(&tokens, free_token);
Translated translated = init_translator(); start = clock();
translate(&translated, &ast); 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); darray_free(&ast, free_parsed);
ensure_dir_exists(cache_folder_path);
file = fopen("out.arbin", "wb"); file = fopen(cache_file_path, "wb");
uint64_t regCount = (uint64_t)translated.registerCount;
uint64_t constantsSize = (uint64_t)translated.constants.size; uint64_t constantsSize = (uint64_t)translated.constants.size;
uint64_t bytecodeSize = (uint64_t)translated.bytecode.size; uint64_t bytecodeSize = (uint64_t)translated.bytecode.size;
uint64_t version_number_htole64ed = htole64(version_number); uint32_t version_number_htole32ed = htole32(version_number);
regCount = htole64(regCount); uint64_t net_hash = htole64(hash);
regCount = htole64(regCount);
constantsSize = htole64(constantsSize); constantsSize = htole64(constantsSize);
bytecodeSize = htole64(bytecodeSize); bytecodeSize = htole64(bytecodeSize);
fwrite(&FILE_IDENTIFIER, sizeof(char), strlen(FILE_IDENTIFIER), file); fwrite(&FILE_IDENTIFIER, sizeof(char), strlen(FILE_IDENTIFIER), file);
fwrite(&version_number_htole64ed, sizeof(uint64_t), 1, file); fwrite(&version_number_htole32ed, sizeof(uint32_t), 1, file);
fwrite(&regCount, sizeof(uint64_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(&constantsSize, sizeof(uint64_t), 1, file);
fwrite(&bytecodeSize, sizeof(uint64_t), 1, file); fwrite(&bytecodeSize, sizeof(uint64_t), 1, file);
fwrite(translated.constants.data, 1, translated.constants.size, file); fwrite(translated.constants.data, 1, translated.constants.size, file);
@@ -72,7 +285,39 @@ int main(int argc, char *argv[]) {
translated.bytecode.size, file); translated.bytecode.size, file);
fclose(file); fclose(file);
}
start = clock();
RuntimeState state = init_runtime_state(translated);
Stack main_scope = create_scope(NULL);
ArErr err = runtime(translated, state, main_scope);
free(state.registers);
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_translator(&translated);
return (Execution){err, main_scope};
}
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
ar_memory_init();
generate_siphash_key(siphash_key);
init_types();
char *CWD = get_current_directory();
if (argc <= 1)
return -1;
char *path_non_absolute = argv[1];
char path[FILENAME_MAX];
cwk_path_get_absolute(CWD, path_non_absolute, path, sizeof(path));
free(CWD);
Execution resp = execute(path);
if (resp.err.exists) {
output_err(resp.err);
return -1;
}
return 0; return 0;
} }

View File

@@ -1,10 +1,9 @@
#include "memory.h" #include "memory.h"
#include <gc.h>
#include <gc/gc.h> #include <gc/gc.h>
#include <gmp.h> #include <gmp.h>
#include <stdio.h>
#include <stdlib.h> // for malloc/free (temp arena fallback) #include <stdlib.h> // for malloc/free (temp arena fallback)
#include <string.h> #include <string.h>
#include <stdio.h>
void *checked_malloc(size_t size) { void *checked_malloc(size_t size) {
void *ptr = malloc(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); return GC_realloc(ptr, new_size);
} }
void gmp_gc_free(void *ptr, size_t size) { void gmp_gc_free(void *ptr, size_t size) {
(void)size; // Boehm GC manages this itself (void)size; // Boehm GC manages this itself
// No-op — memory will be collected automatically // 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); mp_set_memory_functions(GC_malloc, gmp_gc_realloc, gmp_gc_free);
} }
void *ar_alloc(size_t size) { return GC_MALLOC(size); } 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); } void *ar_alloc_atomic(size_t size) { return GC_MALLOC_ATOMIC(size); }
char *ar_strdup(const char *str) { char *ar_strdup(const char *str) {

View File

@@ -2,8 +2,12 @@
#define ARGON_MEMORY_H #define ARGON_MEMORY_H
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <gc/gc.h>
// GC-managed allocations // 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(size_t size);
void *ar_alloc_atomic(size_t size); void *ar_alloc_atomic(size_t size);
char *ar_strdup(const char *str); char *ar_strdup(const char *str);

View File

@@ -1,51 +1,72 @@
#include "access.h" #include "access.h"
#include "../../../lexer/token.h" #include "../../../lexer/token.h"
#include "../../../memory.h" #include "../../../memory.h"
#include "../../string/string.h"
#include "../../parser.h" #include "../../parser.h"
#include "../../string/string.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ParsedValue *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); Token *first_token = darray_get(tokens, *index);
(*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;
parsedValue->type = AST_ACCESS;
parsedValue->data = parsedAccess;
free(to_access); free(to_access);
darray_init(&parsedAccess->access, sizeof(ParsedValue)); darray_init(&parsedAccess->access, sizeof(ParsedValue));
if (first_token->type == TOKEN_DOT) { if (first_token->type == TOKEN_DOT) {
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
ParsedValue *parsedString = parse_string(token, false); ParsedValueReturn parsedString = parse_string(token, false);
darray_push(&parsedAccess->access, parsedString); if (parsedString.err.exists) {
free(parsedString); free_parsed(parsedValue);
free(parsedValue);
return parsedString;
}
darray_push(&parsedAccess->access, parsedString.value);
free(parsedString.value);
parsedAccess->access_fields = true;
} else { } else {
parsedAccess->access_fields = false;
Token *token = first_token;
while (true) { while (true) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
ParsedValue *parsedValue = parse_token(file, tokens, index, true); 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, parsedValue); darray_push(&parsedAccess->access, parsedValue);
free(parsedValue); free(parsedValue);
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
Token *token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RBRACKET) { if (token->type == TOKEN_RBRACKET) {
break; break;
} else if (token->type != TOKEN_COLON) { } else if (token->type != TOKEN_COLON) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line,
token->line, token->column); token->column);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
(*index)++; (*index)++;
} }
} }
parsedValue->type = AST_ACCESS;
parsedValue->data = parsedAccess;
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_access(void *ptr) { void free_parse_access(void *ptr) {

View File

@@ -5,11 +5,13 @@
typedef struct { typedef struct {
ParsedValue to_access; ParsedValue to_access;
bool access_fields;
DArray access; DArray access;
} ParsedAccess; } ParsedAccess;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_access(char*file,DArray *tokens, size_t * index, ParsedValue * to_access); ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
ParsedValue *to_access);
void free_parse_access(void *ptr); void free_parse_access(void *ptr);

View File

@@ -7,8 +7,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_assign(char *file, DArray *tokens, ParsedValue *assign_to, ParsedValueReturn parse_assign(char *file, DArray *tokens,
size_t *index) { ParsedValue *assign_to, size_t *index) {
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
switch (assign_to->type) { switch (assign_to->type) {
case AST_IDENTIFIER: case AST_IDENTIFIER:
@@ -18,36 +18,53 @@ ParsedValue *parse_assign(char *file, DArray *tokens, ParsedValue *assign_to,
ParsedCall *call = assign_to->data; ParsedCall *call = assign_to->data;
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) { if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) {
fprintf(stderr, free_parsed(assign_to);
"%s:%zu:%zu error: parameter names need to start with a letter " free(assign_to);
return (ParsedValueReturn){
create_err(
token->line, token->column, token->length, file, "Syntax Error",
"parameter names need to start with a letter "
"or _, " "or _, "
"only use letters, digits, or _, and can't be keywords.\n", "only use letters, digits, or _, and can't be keywords."),
file, token->line, token->column); NULL};
exit(EXIT_FAILURE);
} }
} }
break; break;
default: default:;
fprintf(stderr, "%s:%zu:%zu error: can't assign to %s\n", file, token->line, ArErr err = create_err(token->line, token->column,
token->column, ValueTypeNames[assign_to->type]); token->length, file, "Syntax Error",
exit(EXIT_FAILURE); "can't assign to %s",
ValueTypeNames[assign_to->type]);
free_parsed(assign_to);
free(assign_to);
return (ParsedValueReturn){err,
NULL};
} }
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign)); ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
assign->to = assign_to; assign->to = assign_to;
assign->type = token->type; assign->type = token->type;
(*index)++;
error_if_finished(file, tokens, index);
token = darray_get(tokens, *index);
assign->from = parse_token(file, tokens, index, true);
if (!assign->from) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line,
token->column);
exit(EXIT_FAILURE);
}
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_ASSIGN; parsedValue->type = AST_ASSIGN;
parsedValue->data = assign; parsedValue->data = assign;
return parsedValue; (*index)++;
error_if_finished(file, tokens, index);
token = darray_get(tokens, *index);
ParsedValueReturn from = parse_token(file, tokens, index, true);
if (from.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return from;
}
assign->from = from.value;
if (!assign->from) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
}
return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_assign(void *ptr) { void free_parse_assign(void *ptr) {
@@ -55,7 +72,9 @@ void free_parse_assign(void *ptr) {
ParsedAssign *parsedAssign = parsedValue->data; ParsedAssign *parsedAssign = parsedValue->data;
free_parsed(parsedAssign->to); free_parsed(parsedAssign->to);
free(parsedAssign->to); free(parsedAssign->to);
if (parsedAssign->from) {
free_parsed(parsedAssign->from); free_parsed(parsedAssign->from);
free(parsedAssign->from); free(parsedAssign->from);
}
free(parsedAssign); free(parsedAssign);
} }

View File

@@ -9,8 +9,8 @@ typedef struct {
ParsedValue * from; ParsedValue * from;
} ParsedAssign; } ParsedAssign;
ParsedValue *parse_assign(char*file, DArray *tokens, ParsedValueReturn parse_assign(char *file, DArray *tokens, ParsedValue *assign_to,
ParsedValue *assign_to, size_t *index); size_t *index);
void free_parse_assign(void*ptr); void free_parse_assign(void*ptr);

View File

@@ -6,7 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ParsedValue *parse_call(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_call(char *file, DArray *tokens, size_t *index,
ParsedValue *to_call) { ParsedValue *to_call) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
ParsedCall *call = checked_malloc(sizeof(ParsedCall)); ParsedCall *call = checked_malloc(sizeof(ParsedCall));
@@ -21,9 +21,26 @@ ParsedValue *parse_call(char *file, DArray *tokens, size_t *index,
while ((*index) < tokens->size) { while ((*index) < tokens->size) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
ParsedValue *parsedArg = parse_token(file, tokens, index, true); ParsedValueReturn parsedArg = parse_token(file, tokens, index, true);
darray_push(&call->args, parsedArg); if (parsedArg.err.exists) {
free(parsedArg); free_parsed(to_call);
free(to_call);
free_parsed(parsedValue);
free(parsedValue);
return parsedArg;
} else if (!parsedArg.value) {
free_parsed(to_call);
free(to_call);
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected argument"),
NULL};
}
darray_push(&call->args, parsedArg.value);
free(parsedArg.value);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
@@ -40,7 +57,7 @@ ParsedValue *parse_call(char *file, DArray *tokens, size_t *index,
} }
} }
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parse_call(void *ptr) { void free_parse_call(void *ptr) {
@@ -49,5 +66,6 @@ void free_parse_call(void *ptr) {
darray_free(&parsedCall->args, free_parsed); darray_free(&parsedCall->args, free_parsed);
free_parsed(parsedCall->to_call); free_parsed(parsedCall->to_call);
free(parsedCall->to_call);
free(parsedCall); free(parsedCall);
} }

View File

@@ -9,7 +9,7 @@ typedef struct {
} ParsedCall; } ParsedCall;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_call(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_call(char *file, DArray *tokens, size_t *index,
ParsedValue *to_call); ParsedValue *to_call);
void free_parse_call(void *ptr); void free_parse_call(void *ptr);

View File

@@ -4,9 +4,9 @@
#include <string.h> #include <string.h>
#include "../../../memory.h" #include "../../../memory.h"
ParsedValue *parse_identifier(Token *token) { ParsedValueReturn parse_identifier(Token *token) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_IDENTIFIER; parsedValue->type = AST_IDENTIFIER;
parsedValue->data = strcpy(checked_malloc(strlen(token->value) + 1), token->value); parsedValue->data = strcpy(checked_malloc(strlen(token->value) + 1), token->value);
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }

View File

@@ -4,6 +4,6 @@
#include "../../../lexer/token.h" // for Token #include "../../../lexer/token.h" // for Token
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue * parse_identifier(Token * token); ParsedValueReturn parse_identifier(Token *token);
#endif // IDENTIFIER_H #endif // IDENTIFIER_H

View File

@@ -1,13 +1,16 @@
#include "declaration.h" #include "declaration.h"
#include "../../hash_data/hash_data.h"
#include "../../hashmap/hashmap.h"
#include "../../lexer/token.h" #include "../../lexer/token.h"
#include "../../memory.h" #include "../../memory.h"
#include "../function/function.h"
#include "../literals/literals.h" #include "../literals/literals.h"
#include "../parser.h" #include "../parser.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_declaration(char *file, DArray *tokens, size_t *index) {
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
@@ -22,31 +25,36 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
darray_push(declarations, &_declaration); darray_push(declarations, &_declaration);
ParsedSingleDeclaration *declaration = ParsedSingleDeclaration *declaration =
darray_get(declarations, declarations->size - 1); darray_get(declarations, declarations->size - 1);
declaration->is_function = false; bool isFunction = false;
DArray parameters;
declaration->from = parse_null(); declaration->from = parse_null();
if (token->type != TOKEN_IDENTIFIER) { if (token->type != TOKEN_IDENTIFIER) {
fprintf(stderr, "%s:%zu:%zu error: declaration requires an identifier\n", free_parsed(parsedValue);
file, token->line, token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "declaration requires an identifier"),
NULL};
} }
declaration->name = declaration->name =
strcpy(checked_malloc(strlen(token->value) + 1), token->value); strcpy(checked_malloc(strlen(token->value) + 1), token->value);
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_LPAREN) { if (token->type == TOKEN_LPAREN) {
declaration->is_function = true; isFunction = true;
darray_init(&declaration->parameters, sizeof(char *)); struct hashmap *parameters_hashmap = createHashmap();
darray_init(&parameters, sizeof(char *));
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type == TOKEN_RPAREN) { if (token->type == TOKEN_RPAREN) {
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
} else { } else {
while ((*index) < tokens->size) { while ((*index) < tokens->size) {
@@ -54,16 +62,33 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type != TOKEN_IDENTIFIER) { if (token->type != TOKEN_IDENTIFIER) {
fprintf(stderr, free_parsed(parsedValue);
"%s:%zu:%zu error: parameter names need to start with a " free(parsedValue);
"letter or _, only use letters, digits, or _, and can't be " return (ParsedValueReturn){
"keywords.\n", create_err(
file, token->line, token->column); token->line, token->column, token->length, file,
exit(EXIT_FAILURE); "Syntax Error",
"parameter names need to start with a letter or _, only "
"use letters, digits, or _, and can't be keywords."),
NULL};
} }
char *parameter_name = uint64_t hash =
strcpy(checked_malloc(strlen(token->value) + 1), token->value); siphash64_bytes(token->value, token->length, siphash_key);
darray_push(&declaration->parameters, &parameter_name); if (hashmap_lookup(parameters_hashmap, hash) != NULL) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error",
"duplicate argument in function "
"definition"),
NULL};
}
char *parameter_name = checked_malloc(token->length + 1);
strcpy(parameter_name, token->value);
hashmap_insert(parameters_hashmap, hash, parameter_name, (void *)1,
0);
darray_push(&parameters, &parameter_name);
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
@@ -72,18 +97,22 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
if (token->type == TOKEN_RPAREN) { if (token->type == TOKEN_RPAREN) {
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
break; break;
} else if (token->type != TOKEN_COMMA) { } else if (token->type != TOKEN_COMMA) {
fprintf(stderr, "%s:%zu:%zu error: expected comma\n", file, free_parsed(parsedValue);
token->line, token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected comma"),
NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
} }
} }
hashmap_free(parameters_hashmap, NULL);
} }
if (token->type == TOKEN_ASSIGN) { if (token->type == TOKEN_ASSIGN) {
(*index)++; (*index)++;
@@ -91,16 +120,30 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
free(declaration->from); free(declaration->from);
declaration->from = parse_token(file, tokens, index, true); ParsedValueReturn from = parse_token(file, tokens, index, true);
if (from.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return from;
}
declaration->from = from.value;
if (!declaration->from) { if (!declaration->from) {
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, free_parsed(parsedValue);
token->column); free(parsedValue);
exit(EXIT_FAILURE); return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected body"),
NULL};
}
}
if (isFunction) {
declaration->from = create_parsed_function(declaration->name, parameters,
declaration->from);
} }
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
break; break;
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
}
size_t count = skip_newlines_and_indents(tokens, index); size_t count = skip_newlines_and_indents(tokens, index);
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
break; break;
@@ -115,7 +158,7 @@ ParsedValue *parse_declaration(char *file, DArray *tokens, size_t *index) {
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
} }
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_string(void *ptr) { void free_string(void *ptr) {
@@ -126,12 +169,13 @@ void free_string(void *ptr) {
void free_single_declaration(void *ptr) { void free_single_declaration(void *ptr) {
ParsedSingleDeclaration *declaration = ptr; ParsedSingleDeclaration *declaration = ptr;
if (declaration->name)
free(declaration->name); free(declaration->name);
if (declaration->is_function) if (declaration->from) {
darray_free(&declaration->parameters, free_string);
free_parsed(declaration->from); free_parsed(declaration->from);
free(declaration->from); free(declaration->from);
} }
}
void free_declaration(void *ptr) { void free_declaration(void *ptr) {
ParsedValue *parsedValue = ptr; ParsedValue *parsedValue = ptr;

View File

@@ -5,14 +5,11 @@
typedef struct { typedef struct {
char * name; char * name;
bool is_function;
DArray parameters; // string[]
ParsedValue * from; ParsedValue * from;
} ParsedSingleDeclaration; } ParsedSingleDeclaration;
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_declaration(char *file, DArray *tokens, ParsedValueReturn parse_declaration(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_declaration(void *ptr); void free_declaration(void *ptr);

View File

@@ -7,7 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_dictionary(char *file, DArray *tokens, size_t *index) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_DICTIONARY; parsedValue->type = AST_DICTIONARY;
DArray *dictionary = checked_malloc(sizeof(DArray)); DArray *dictionary = checked_malloc(sizeof(DArray));
@@ -23,17 +23,29 @@ ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) {
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
size_t keyIndex = *index; size_t keyIndex = *index;
Token *keyToken = darray_get(tokens, *index); Token *keyToken = darray_get(tokens, *index);
ParsedValue *key; ParsedValueReturn key;
if (keyToken->type == TOKEN_IDENTIFIER) { if (keyToken->type == TOKEN_IDENTIFIER) {
(*index)++; (*index)++;
key = parse_string(keyToken, false); key = parse_string(keyToken, false);
} else { } else {
key = parse_token(file, tokens, index, true); key = parse_token(file, tokens, index, true);
} }
if (key.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return key;
} else if (!key.value) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file,
"Syntax Error", "expected key"),
NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
ParsedValue *value; ParsedValueReturn value;
bool tobreak = false; bool tobreak = false;
switch (token->type) { switch (token->type) {
case TOKEN_COLON: case TOKEN_COLON:
@@ -41,6 +53,22 @@ ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
value = parse_token(file, tokens, index, true); value = parse_token(file, tokens, index, true);
if (value.err.exists) {
free_parsed(parsedValue);
free(parsedValue);
free_parsed(key.value);
free(key.value);
return value;
} else if (!value.value) {
free_parsed(parsedValue);
free(parsedValue);
free_parsed(key.value);
free(key.value);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected value"),
NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
@@ -63,7 +91,7 @@ ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) {
token->column); token->column);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
ParsedDictionaryEntry entry = {key, value}; ParsedDictionaryEntry entry = {key.value, value.value};
darray_push(dictionary, &entry); darray_push(dictionary, &entry);
if (tobreak) { if (tobreak) {
break; break;
@@ -73,7 +101,7 @@ ParsedValue *parse_dictionary(char *file, DArray *tokens, size_t *index) {
} }
} }
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_dictionary_entry(void *ptr) { void free_dictionary_entry(void *ptr) {
@@ -88,5 +116,5 @@ void free_parsed_dictionary(void *ptr) {
ParsedValue *parsedValue = ptr; ParsedValue *parsedValue = ptr;
DArray *parsed_dictionary = parsedValue->data; DArray *parsed_dictionary = parsedValue->data;
darray_free(parsed_dictionary, free_dictionary_entry); darray_free(parsed_dictionary, free_dictionary_entry);
free(parsedValue->data); free(parsed_dictionary);
} }

View File

@@ -8,8 +8,7 @@ typedef struct {
ParsedValue * value; ParsedValue * value;
} ParsedDictionaryEntry; } ParsedDictionaryEntry;
ParsedValue *parse_dictionary(char *file, DArray *tokens, ParsedValueReturn parse_dictionary(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_parsed_dictionary(void *ptr); void free_parsed_dictionary(void *ptr);

View File

@@ -24,7 +24,7 @@ void free_string_dowrap(void *ptr) {
free(str); free(str);
} }
ParsedValue *parse_dowrap(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_dowrap(char *file, DArray *tokens, size_t *index) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_DOWRAP; parsedValue->type = AST_DOWRAP;
DArray *dowrap_parsed = checked_malloc(sizeof(DArray)); DArray *dowrap_parsed = checked_malloc(sizeof(DArray));
@@ -32,9 +32,13 @@ ParsedValue *parse_dowrap(char *file, DArray *tokens, size_t *index) {
parsedValue->data = dowrap_parsed; parsedValue->data = dowrap_parsed;
(*index)++; (*index)++;
if ((*index) >= tokens->size) if ((*index) >= tokens->size)
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
if (token->type != TOKEN_NEW_LINE) { if (token->type != TOKEN_NEW_LINE) {
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line, fprintf(stderr, "%s:%zu:%zu error: syntax error\n", file, token->line,
token->column); token->column);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -93,13 +97,19 @@ ParsedValue *parse_dowrap(char *file, DArray *tokens, size_t *index) {
for (size_t i = 0; i < temp_index_count; i++) { for (size_t i = 0; i < temp_index_count; i++) {
darray_pop(&dowrap_tokens, NULL); darray_pop(&dowrap_tokens, NULL);
} }
parser(file, dowrap_parsed, &dowrap_tokens, false); ArErr err = parser(file, dowrap_parsed, &dowrap_tokens, false);
darray_free(&dowrap_tokens, NULL); darray_free(&dowrap_tokens, NULL);
darray_free(&to_free, free_string_dowrap); darray_free(&to_free, free_string_dowrap);
return parsedValue; if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
return (ParsedValueReturn){no_err, parsedValue};
} }
void free_dowrap(void *ptr) { void free_dowrap(void *ptr) {

View File

@@ -4,8 +4,7 @@
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue *parse_dowrap(char *file, DArray *tokens, ParsedValueReturn parse_dowrap(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_dowrap(void *ptr); void free_dowrap(void *ptr);

View File

@@ -0,0 +1,31 @@
#include "function.h"
#include "../../memory.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

@@ -6,7 +6,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) { void free_conditional(void *ptr) {
ParsedConditional *conditional = ptr;
if (conditional->condition) {
free_parsed(conditional->condition);
free(conditional->condition);
}
free_parsed(conditional->content);
free(conditional->content);
}
ParsedValueReturn parse_if(char *file, DArray *tokens, size_t *index) {
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
@@ -35,28 +45,50 @@ ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) {
} }
} }
ParsedValue *condition = NULL; ParsedValueReturn condition = {no_err, NULL};
if (token->type != TOKEN_ELSE) { if (token->type != TOKEN_ELSE) {
// Parse ( condition ) // Parse ( condition )
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type != TOKEN_LPAREN) { if (token->type != TOKEN_LPAREN) {
fprintf(stderr, "%s:%zu:%zu error: expected '(' after if\n", file, darray_free(parsed_if, free_conditional);
token->line, token->column); free(parsed_if);
exit(EXIT_FAILURE); return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected '(' after if"),
NULL};
} }
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
condition = parse_token(file, tokens, index, true); condition = parse_token(file, tokens, index, true);
if (condition.err.exists) {
darray_free(parsed_if, free_conditional);
free(parsed_if);
return condition;
} else if (!condition.value) {
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected condition"),
NULL};
}
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
if (token->type != TOKEN_RPAREN) { if (token->type != TOKEN_RPAREN) {
fprintf(stderr, "%s:%zu:%zu error: missing closing ')' in condition\n", if (condition.value) {
file, token->line, token->column); free_parsed(condition.value);
exit(EXIT_FAILURE); free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "missing closing ')' in condition"),
NULL};
} }
(*index)++; (*index)++;
@@ -64,15 +96,32 @@ ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) {
} }
// Parse the body // Parse the body
ParsedValue *parsed_content = parse_token(file, tokens, index, false); ParsedValueReturn parsed_content = parse_token(file, tokens, index, false);
if (!parsed_content) { if (parsed_content.err.exists) {
fprintf(stderr, "%s:%zu:%zu error: expected body after condition\n", file, if (condition.value) {
token->line, token->column); free_parsed(condition.value);
exit(EXIT_FAILURE); free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return parsed_content;
} }
ParsedConditional conditional = {condition, parsed_content}; if (!parsed_content.value) {
if (condition.value) {
free_parsed(condition.value);
free(condition.value);
}
darray_free(parsed_if, free_conditional);
free(parsed_if);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
NULL};
}
ParsedConditional conditional = {condition.value, parsed_content.value};
darray_push(parsed_if, &conditional); darray_push(parsed_if, &conditional);
expect_conditional = expect_conditional =
@@ -98,22 +147,12 @@ ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) {
// printf(" - content value type: %d\n", cond->content->type); // printf(" - content value type: %d\n", cond->content->type);
// } // }
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
}
void free_conditional(void *ptr) {
ParsedConditional *conditional = ptr;
if (conditional->condition) {
free_parsed(conditional->condition);
free(conditional->condition);
}
free_parsed(conditional->content);
free(conditional->content);
} }
void free_parsed_if(void *ptr) { void free_parsed_if(void *ptr) {
ParsedValue *parsedValue = ptr; ParsedValue *parsedValue = ptr;
DArray *parsed_if = parsedValue->data; DArray *parsed_if = parsedValue->data;
darray_free(parsed_if, free_conditional); darray_free(parsed_if, free_conditional);
free(parsedValue->data); free(parsed_if);
} }

View File

@@ -8,8 +8,7 @@ typedef struct {
ParsedValue *content; ParsedValue *content;
} ParsedConditional; } ParsedConditional;
ParsedValue *parse_if(char *file, DArray *tokens, ParsedValueReturn parse_if(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_parsed_if(void *ptr); void free_parsed_if(void *ptr);

View File

@@ -6,7 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
ParsedValue *parse_list(char *file, DArray *tokens, size_t *index) { ParsedValueReturn parse_list(char *file, DArray *tokens, size_t *index) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_LIST; parsedValue->type = AST_LIST;
DArray *list = checked_malloc(sizeof(DArray)); DArray *list = checked_malloc(sizeof(DArray));
@@ -19,9 +19,14 @@ ParsedValue *parse_list(char *file, DArray *tokens, size_t *index) {
if (token->type != TOKEN_RBRACKET) { if (token->type != TOKEN_RBRACKET) {
while (true) { while (true) {
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
ParsedValue *parsedValue = parse_token(file, tokens, index, true); ParsedValueReturn parsedItem = parse_token(file, tokens, index, true);
darray_push(list, parsedValue); if (parsedItem.err.exists) {
free_parsed(parsedValue);
free(parsedValue); free(parsedValue);
return parsedItem;
}
darray_push(list, parsedItem.value);
free(parsedItem.value);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
skip_newlines_and_indents(tokens, index); skip_newlines_and_indents(tokens, index);
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
@@ -38,12 +43,12 @@ ParsedValue *parse_list(char *file, DArray *tokens, size_t *index) {
} }
} }
(*index)++; (*index)++;
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }
void free_parsed_list(void *ptr) { void free_parsed_list(void *ptr) {
ParsedValue *parsedValue = ptr; ParsedValue *parsedValue = ptr;
DArray *parsed_list = parsedValue->data; DArray *parsed_list = parsedValue->data;
darray_free(parsed_list, free_parsed); darray_free(parsed_list, free_parsed);
free(parsedValue->data); free(parsed_list);
} }

View File

@@ -3,8 +3,7 @@
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
#include "../parser.h" #include "../parser.h"
ParsedValue *parse_list(char *file, DArray *tokens, ParsedValueReturn parse_list(char *file, DArray *tokens, size_t *index);
size_t *index);
void free_parsed_list(void *ptr); void free_parsed_list(void *ptr);

View File

@@ -150,9 +150,9 @@
// return 0; // return 0;
// } // }
ParsedValue *parse_number(Token *token) { ParsedValueReturn parse_number(Token *token) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_NUMBER; parsedValue->type = AST_NUMBER;
parsedValue->data = strdup(token->value); parsedValue->data = strdup(token->value);
return parsedValue; return (ParsedValueReturn){no_err, parsedValue};
} }

View File

@@ -4,6 +4,6 @@
#include "../../lexer/token.h" // for Token #include "../../lexer/token.h" // for Token
// Function declaration for parsing an identifier // Function declaration for parsing an identifier
ParsedValue * parse_number(Token * token); ParsedValueReturn parse_number(Token *token);
#endif // NUMBER_H #endif // NUMBER_H

View File

@@ -6,9 +6,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.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) { if (to_operate_on->size == 1) {
return darray_get(to_operate_on, 0); return *((ParsedValue *)darray_get(to_operate_on, 0));
} }
TokenType operation = 0; TokenType operation = 0;
DArray positions; DArray positions;
@@ -23,10 +23,10 @@ ParsedValue *convert_to_operation(DArray *to_operate_on, DArray *operations) {
} }
darray_push(&positions, &i); darray_push(&positions, &i);
} }
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue parsedValue;
parsedValue->type = AST_OPERATION; parsedValue.type = AST_OPERATION;
ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation)); ParsedOperation *operationStruct = checked_malloc(sizeof(ParsedOperation));
parsedValue->data = operationStruct; parsedValue.data = operationStruct;
operationStruct->operation = operation; operationStruct->operation = operation;
darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue)); darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue));
size_t last_position = 0; size_t last_position = 0;
@@ -37,21 +37,24 @@ ParsedValue *convert_to_operation(DArray *to_operate_on, DArray *operations) {
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, last_position, *position);
darray_push(&operationStruct->to_operate_on, 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);
last_position = (*position); last_position = (*position);
to_operate_on_last_position = (*position) + 1; to_operate_on_last_position = (*position) + 1;
} }
DArray to_operate_on_slice = DArray to_operate_on_slice = darray_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_slice(operations, last_position, operations->size); DArray operations_slice =
darray_push(&operationStruct->to_operate_on, darray_slice(operations, last_position, operations->size);
convert_to_operation(&to_operate_on_slice, &operations_slice)); ParsedValue result =
convert_to_operation(&to_operate_on_slice, &operations_slice);
darray_push(&operationStruct->to_operate_on, &result);
darray_free(&positions, NULL); darray_free(&positions, NULL);
return parsedValue; return parsedValue;
} }
ParsedValue *parse_operations(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_operations(char *file, DArray *tokens, size_t *index,
ParsedValue *first_parsed_value) { ParsedValue *first_parsed_value) {
DArray to_operate_on; DArray to_operate_on;
darray_init(&to_operate_on, sizeof(ParsedValue)); darray_init(&to_operate_on, sizeof(ParsedValue));
@@ -75,15 +78,29 @@ ParsedValue *parse_operations(char *file, DArray *tokens, size_t *index,
darray_push(&operations, &token->type); darray_push(&operations, &token->type);
(*index)++; (*index)++;
error_if_finished(file, tokens, index); error_if_finished(file, tokens, index);
ParsedValue *parsedValue = ParsedValueReturn parsedValue =
parse_token_full(file, tokens, index, true, false); parse_token_full(file, tokens, index, true, false);
darray_push(&to_operate_on, parsedValue); if (parsedValue.err.exists) {
free(parsedValue); darray_free(&to_operate_on, free_parsed);
darray_free(&operations, NULL);
return parsedValue;
} else if (!parsedValue.value) {
darray_free(&to_operate_on, free_parsed);
darray_free(&operations, NULL);
return (ParsedValueReturn){
create_err(token->line, token->column, token->length, file,
"Syntax Error", "expected value"),
NULL};
} }
ParsedValue *output = convert_to_operation(&to_operate_on, &operations); darray_push(&to_operate_on, parsedValue.value);
free(parsedValue.value);
}
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(&to_operate_on, NULL);
darray_free(&operations, NULL); darray_free(&operations, NULL);
return output; return (ParsedValueReturn){no_err,parsedValue};
} }
void free_operation(void *ptr) { void free_operation(void *ptr) {

View File

@@ -8,7 +8,8 @@ typedef struct {
DArray to_operate_on; // ParsedValue[] DArray to_operate_on; // ParsedValue[]
} ParsedOperation; } ParsedOperation;
ParsedValue *parse_operations(char*file,DArray *tokens, size_t * index, ParsedValue * first_parsed_value); ParsedValueReturn parse_operations(char *file, DArray *tokens, size_t *index,
ParsedValue *first_parsed_value);
void free_operation(void *ptr); void free_operation(void *ptr);

View File

@@ -8,6 +8,7 @@
#include "declaration/declaration.h" #include "declaration/declaration.h"
#include "dictionary/dictionary.h" #include "dictionary/dictionary.h"
#include "dowrap/dowrap.h" #include "dowrap/dowrap.h"
#include "function/function.h"
#include "if/if.h" #include "if/if.h"
#include "list/list.h" #include "list/list.h"
#include "literals/literals.h" #include "literals/literals.h"
@@ -24,7 +25,7 @@
const char *ValueTypeNames[] = { const char *ValueTypeNames[] = {
"string", "assign", "identifier", "number", "if statement", "string", "assign", "identifier", "number", "if statement",
"access", "call", "declaration", "null", "boolean", "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) { void error_if_finished(char *file, DArray *tokens, size_t *index) {
if ((*index) >= tokens->size) { if ((*index) >= tokens->size) {
@@ -53,11 +54,11 @@ size_t skip_newlines_and_indents(DArray *tokens, size_t *index) {
return count; return count;
} }
ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
bool inline_flag, bool process_operations) { bool inline_flag, bool process_operations) {
Token *token = darray_get(tokens, *index); Token *token = darray_get(tokens, *index);
ParsedValue *output = NULL; ParsedValueReturn output;
if (!inline_flag) { if (!inline_flag) {
switch (token->type) { switch (token->type) {
@@ -70,15 +71,15 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
switch (token->type) { switch (token->type) {
case TOKEN_TRUE: case TOKEN_TRUE:
(*index)++; (*index)++;
output = parse_true(); output = (ParsedValueReturn){no_err, parse_true()};
break; break;
case TOKEN_FALSE: case TOKEN_FALSE:
(*index)++; (*index)++;
output = parse_false(); output = (ParsedValueReturn){no_err, parse_false()};
break; break;
case TOKEN_NULL: case TOKEN_NULL:
(*index)++; (*index)++;
output = parse_null(); output = (ParsedValueReturn){no_err, parse_null()};
break; break;
case TOKEN_STRING: case TOKEN_STRING:
(*index)++; (*index)++;
@@ -86,18 +87,20 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
break; break;
case TOKEN_NEW_LINE: case TOKEN_NEW_LINE:
(*index)++; (*index)++;
return NULL; return (ParsedValueReturn){no_err, NULL};
case TOKEN_INDENT: case TOKEN_INDENT:;
Token *token_indent = token;
if (strlen(token->value) > 0 && (*index + 1) < tokens->size) { if (strlen(token->value) > 0 && (*index + 1) < tokens->size) {
token = darray_get(tokens, (*index) + 1); token = darray_get(tokens, (*index) + 1);
if (token->type != TOKEN_NEW_LINE) { if (token->type != TOKEN_NEW_LINE) {
fprintf(stderr, "%s:%zu:%zu error: invalid indentation\n", file, return (ParsedValueReturn){
token->line, token->column); create_err(token_indent->line, token_indent->column, token_indent->length, file,
exit(EXIT_FAILURE); "Syntax Error", "unexpected indent"),
NULL};
} }
} }
(*index)++; (*index)++;
return NULL; return (ParsedValueReturn){no_err, NULL};
case TOKEN_IDENTIFIER: case TOKEN_IDENTIFIER:
(*index)++; (*index)++;
output = parse_identifier(token); output = parse_identifier(token);
@@ -127,6 +130,9 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
// LHS required // LHS required
bool passed = false; bool passed = false;
while (!passed && (*index) < tokens->size) { while (!passed && (*index) < tokens->size) {
if (output.err.exists) {
return output;
}
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
switch (token->type) { switch (token->type) {
case TOKEN_ASSIGN: case TOKEN_ASSIGN:
@@ -137,18 +143,18 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
case TOKEN_ASSIGN_PLUS: case TOKEN_ASSIGN_PLUS:
case TOKEN_ASSIGN_SLASH: case TOKEN_ASSIGN_SLASH:
case TOKEN_ASSIGN_STAR: case TOKEN_ASSIGN_STAR:
output = parse_assign(file, tokens, output, index); output = parse_assign(file, tokens, output.value, index);
break; break;
case TOKEN_LPAREN: case TOKEN_LPAREN:
output = parse_call(file, tokens, index, output); output = parse_call(file, tokens, index, output.value);
break; break;
case TOKEN_DOT: case TOKEN_DOT:
case TOKEN_LBRACKET: case TOKEN_LBRACKET:
output = parse_access(file, tokens, index, output); output = parse_access(file, tokens, index, output.value);
break; break;
SWITCH_OPERATIONS SWITCH_OPERATIONS
if (process_operations) { if (process_operations) {
output = parse_operations(file, tokens, index, output); output = parse_operations(file, tokens, index, output.value);
break; break;
} }
/* fall through */ /* fall through */
@@ -160,18 +166,21 @@ ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index,
return output; return output;
} }
ParsedValue *parse_token(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_token(char *file, DArray *tokens, size_t *index,
bool inline_flag) { bool inline_flag) {
return parse_token_full(file, tokens, index, inline_flag, true); return parse_token_full(file, tokens, index, inline_flag, true);
} }
void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) { ArErr parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) {
size_t index = 0; size_t index = 0;
bool expecting_new_line = false; bool expecting_new_line = false;
while (index < tokens->size) { while (index < tokens->size) {
size_t old_index = index; size_t old_index = index;
ParsedValue *parsed_code = parse_token(file, tokens, &index, inline_flag); ParsedValueReturn parsed_code =
if (parsed_code) { parse_token(file, tokens, &index, inline_flag);
if (parsed_code.err.exists) {
return parsed_code.err;
} else if (parsed_code.value) {
if (expecting_new_line) { if (expecting_new_line) {
Token *token = darray_get(tokens, old_index); Token *token = darray_get(tokens, old_index);
fprintf(stderr, "%s:%zu:%zu error: expected a new line\n", file, fprintf(stderr, "%s:%zu:%zu error: expected a new line\n", file,
@@ -179,8 +188,8 @@ void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
expecting_new_line = true; expecting_new_line = true;
darray_push(parsed, parsed_code); darray_push(parsed, parsed_code.value);
free(parsed_code); free(parsed_code.value);
} else { } else {
expecting_new_line = false; expecting_new_line = false;
} }
@@ -232,5 +241,7 @@ void free_parsed(void *ptr) {
case AST_DICTIONARY: case AST_DICTIONARY:
free_parsed_dictionary(parsed); free_parsed_dictionary(parsed);
break; break;
case AST_FUNCTION:
free_function(parsed);
} }
} }

View File

@@ -2,10 +2,12 @@
#define PARSER_H #define PARSER_H
#include "../dynamic_array/darray.h" #include "../dynamic_array/darray.h"
#include "../err.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#define SWITCH_OPERATIONS case TOKEN_AND:\ #define SWITCH_OPERATIONS \
case TOKEN_AND: \
case TOKEN_OR: \ case TOKEN_OR: \
case TOKEN_NOT_IN: \ case TOKEN_NOT_IN: \
case TOKEN_IN: \ case TOKEN_IN: \
@@ -39,7 +41,8 @@ typedef enum {
AST_DOWRAP, AST_DOWRAP,
AST_OPERATION, AST_OPERATION,
AST_LIST, AST_LIST,
AST_DICTIONARY AST_DICTIONARY,
AST_FUNCTION
} ValueType; } ValueType;
extern const char *ValueTypeNames[]; extern const char *ValueTypeNames[];
@@ -49,12 +52,17 @@ typedef struct {
void *data; void *data;
} ParsedValue; } ParsedValue;
void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag); typedef struct {
ArErr err;
ParsedValue *value;
} ParsedValueReturn;
ParsedValue *parse_token_full(char *file, DArray *tokens, size_t *index, ArErr parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag);
ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
bool inline_flag, bool process_operations); bool inline_flag, bool process_operations);
ParsedValue *parse_token(char *file, DArray *tokens, size_t *index, ParsedValueReturn parse_token(char *file, DArray *tokens, size_t *index,
bool inline_flag); bool inline_flag);
void free_parsed(void *ptr); void free_parsed(void *ptr);

View File

@@ -245,7 +245,7 @@ char *unquote(char *str, size_t *decoded_len) {
return unescaped; return unescaped;
} }
ParsedValue *parse_string(Token* token, bool to_unquote) { ParsedValueReturn parse_string(Token* token, bool to_unquote) {
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_STRING; parsedValue->type = AST_STRING;
ParsedString *parsedString = checked_malloc(sizeof(ParsedString)); ParsedString *parsedString = checked_malloc(sizeof(ParsedString));
@@ -253,11 +253,19 @@ ParsedValue *parse_string(Token* token, bool to_unquote) {
if (to_unquote) { if (to_unquote) {
parsedString->length = 0; parsedString->length = 0;
parsedString->string = unquote(token->value, &parsedString->length); parsedString->string = unquote(token->value, &parsedString->length);
if (!parsedString->string) {
free(parsedValue);
free(parsedString);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, NULL, "String Error",
"failed to unquote string %s", token->value),
NULL};
}
} else { } else {
parsedString->string = strdup(token->value); parsedString->string = strdup(token->value);
parsedString->length = token->length; parsedString->length = token->length;
} }
return parsedValue; return (ParsedValueReturn){no_err,parsedValue};
} }
void free_parsed_string(void *ptr) { void free_parsed_string(void *ptr) {

View File

@@ -15,7 +15,7 @@ char *swap_quotes(char *input, char quote);
char *unquote(char *str, size_t *decoded_len); char *unquote(char *str, size_t *decoded_len);
ParsedValue *parse_string(Token* token, bool to_unquote); ParsedValueReturn parse_string(Token* token, bool to_unquote);
void free_parsed_string(void *ptr); void free_parsed_string(void *ptr);

22
src/returnTypes.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef RETURN_TYPES_H
#define RETURN_TYPES_H
#include <stdint.h>
#include "arobject.h"
#define ERR_MSG_MAX_LEN 256
typedef struct ArErr {
bool exists;
char *path;
int64_t line;
int64_t column;
int length;
char type[32];
char message[ERR_MSG_MAX_LEN];
} ArErr;
typedef struct Execution {
ArErr err;
Stack stack;
} Execution;
#endif // RETURN_TYPES_

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 - 1); }
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,31 @@
#ifndef HASHMAP_GC_H
#define HASHMAP_GC_H
#include <stdint.h>
#include <stdlib.h>
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 <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,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,15 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "../internals/hashmap/hashmap.h"
#include "../runtime.h"
#include <stdbool.h>
extern ArgonObject *BASE_CLASS;
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

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

@@ -0,0 +1,102 @@
#include "runtime.h"
#include "../err.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;
}
ArErr 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;
default:
return create_err(0, 0, 0, NULL, "Runtime Error", "Invalid Opcode %#x", opcode);
}
return no_err;
}
RuntimeState init_runtime_state(Translated translated) {
return (RuntimeState){
checked_malloc(translated.registerCount * sizeof(ArgonObject *)), 0};
}
Stack create_scope(Stack *prev) { return (Stack){NULL, prev}; }
ArErr runtime(Translated translated, RuntimeState state, Stack stack) {
state.head = 0;
while (state.head < translated.bytecode.size) {
ArErr err = run_instruction(&translated, &state, stack);
if (err.exists) {
return err;
}
}
free(state.registers);
return no_err;
}

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

@@ -0,0 +1,25 @@
#ifndef RUNTIME_H
#define RUNTIME_H
#include "../translator/translator.h"
#include "internals/hashmap/hashmap.h"
#include "../returnTypes.h"
typedef struct {
ArgonObject **registers;
size_t head;
} RuntimeState;
void init_types();
uint64_t pop_bytecode(Translated *translated, RuntimeState *state);
ArErr run_instruction(Translated *translated, RuntimeState *state,
struct Stack stack);
RuntimeState init_runtime_state(Translated translated);
Stack create_scope(Stack *prev);
ArErr runtime(Translated translated, RuntimeState state, Stack stack);
#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 "declaration.h"
#include "../../parser/declaration/declaration.h" #include "../../parser/declaration/declaration.h"
#include "../translator.h"
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
size_t translate_parsed_declaration(Translated *translated, size_t translate_parsed_declaration(Translated *translated,
ParsedValue *parsedValue) { DArray delcarations) {
DArray *delcarations = (DArray *)parsedValue->data; set_registers(translated, 1);
set_registers(translated, 2);
size_t first = 0; size_t first = 0;
for (size_t i = 0; i < delcarations->size; i++) { for (size_t i = 0; i < delcarations.size; i++) {
// TODO: add function delclaration ParsedSingleDeclaration *singleDeclaration = darray_get(&delcarations, i);
ParsedSingleDeclaration*singleDeclaration = darray_get(delcarations, i);
size_t temp = translate_parsed(translated, singleDeclaration->from); 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 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_byte(translated, OP_DECLARE);
push_instruction_code(translated, 1);
push_instruction_code(translated, TYPE_OP_STRING);
push_instruction_code(translated, length); push_instruction_code(translated, length);
push_instruction_code(translated, offset); push_instruction_code(translated, offset);
push_instruction_byte(translated, 0);
push_instruction_code(translated, OP_DECLARE);
push_instruction_code(translated, 0);
push_instruction_code(translated, 1);
} }
if (delcarations->size != 1) { if (delcarations.size != 1) {
push_instruction_code(translated, OP_LOAD_NULL); push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_code(translated, 0); push_instruction_byte(translated, 0);
} }
return first; return first;
} }

View File

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

@@ -0,0 +1,15 @@
#include "../translator.h"
#include "identifier.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
size_t translate_parsed_identifier(Translated *translated, char* identifier) {
size_t length = strlen(identifier);
size_t identifier_pos = arena_push(&translated->constants, identifier, length);
set_registers(translated, 1);
size_t start = push_instruction_byte(translated, OP_IDENTIFIER);
push_instruction_code(translated,length);
push_instruction_code(translated, identifier_pos);
return start;
}

View File

@@ -0,0 +1,8 @@
#ifndef BYTECODE_IDENTIFIER_H
#define BYTECODE_IDENTIFIER_H
#include "../translator.h"
#include "../../parser/assignable/identifier/identifier.h"
size_t translate_parsed_identifier(Translated *translated, char* identifier);
#endif

View File

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

View File

@@ -2,6 +2,6 @@
#define BYTECODE_NUMBER_H #define BYTECODE_NUMBER_H
#include "../translator.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 #endif

View File

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

View File

@@ -1,7 +1,8 @@
#ifndef BYTECODE_STRING_H #ifndef BYTECODE_STRING_H
#define BYTECODE_STRING_H #define BYTECODE_STRING_H
#include "../translator.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 #endif

View File

@@ -1,5 +1,9 @@
#include "translator.h" #include "translator.h"
#include "../hash_data/hash_data.h"
#include "../hashmap/hashmap.h"
#include "declaration/declaration.h" #include "declaration/declaration.h"
#include "function/function.h"
#include "identifier/identifier.h"
#include "number/number.h" #include "number/number.h"
#include "string/string.h" #include "string/string.h"
#include <stddef.h> #include <stddef.h>
@@ -8,10 +12,17 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.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) { void arena_init(ConstantArena *arena) {
arena->data = checked_malloc(CHUNK_SIZE); arena->data = checked_malloc(CHUNK_SIZE);
arena->capacity = CHUNK_SIZE; arena->capacity = CHUNK_SIZE;
arena->size = 0; arena->size = 0;
arena->hashmap = createHashmap();
} }
void arena_resize(ConstantArena *arena, size_t new_size) { void arena_resize(ConstantArena *arena, size_t new_size) {
@@ -31,6 +42,7 @@ void arena_free(ConstantArena *arena) {
free(arena->data); free(arena->data);
arena->capacity = 0; arena->capacity = 0;
arena->size = 0; arena->size = 0;
hashmap_free(arena->hashmap, NULL);
} }
void *arena_get(ConstantArena *arena, size_t offset) { void *arena_get(ConstantArena *arena, size_t offset) {
@@ -38,43 +50,57 @@ 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) {
if (arena->size >= length) { uint64_t hash = siphash64_bytes(data, length, siphash_key);
for (size_t i = 0; i <= (arena->size - length); i++) {
if (memcmp(data, arena->data + i, length) == 0) { // Look up offset in hashmap
return i; 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); arena_resize(arena, arena->size + length);
size_t offset = arena->size; size_t offset = arena->size;
memcpy(arena->data + arena->size, data, length); memcpy(arena->data + arena->size, data, length);
arena->size += 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; return offset;
} }
Translated init_translator() { Translated init_translator() {
Translated translated; Translated translated;
translated.registerCount = 0; translated.registerCount = 0;
darray_init(&translated.bytecode, sizeof(uint64_t)); darray_init(&translated.bytecode, sizeof(uint8_t));
arena_init(&translated.constants); arena_init(&translated.constants);
return translated; return translated;
} }
void set_instruction_code(Translated *translator, size_t offset, size_t push_instruction_byte(Translated *translator, uint8_t byte) {
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 offset = translator->bytecode.size; size_t offset = translator->bytecode.size;
darray_push(&translator->bytecode, &code); darray_push(&translator->bytecode, &byte);
return offset; 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) if (count > translator->registerCount)
translator->registerCount = count; translator->registerCount = count;
} }
@@ -82,16 +108,23 @@ 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, parsedValue); return translate_parsed_string(translated,
*((ParsedString *)parsedValue->data));
case AST_DECLARATION: case AST_DECLARATION:
return translate_parsed_declaration(translated, parsedValue); return translate_parsed_declaration(translated,
*((DArray *)parsedValue->data));
case AST_NUMBER: case AST_NUMBER:
return translate_parsed_number(translated, parsedValue); return translate_parsed_number(translated, (char *)parsedValue->data, 0);
case AST_NULL: case AST_NULL:
set_registers(translated, 1); set_registers(translated, 1);
size_t output = push_instruction_code(translated, OP_LOAD_NULL); size_t output = push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_code(translated, 0); push_instruction_byte(translated, 0);
return output; return output;
case AST_FUNCTION:
return translate_parsed_function(translated,
(ParsedFunction *)parsedValue->data);
case AST_IDENTIFIER:
return translate_parsed_identifier(translated, (char *)parsedValue->data);
} }
return 0; return 0;
} }

View File

@@ -4,33 +4,37 @@
#include "../dynamic_array/darray.h" #include "../dynamic_array/darray.h"
#include "../memory.h" #include "../memory.h"
#include "../parser/parser.h" #include "../parser/parser.h"
#include "../hashmap/hashmap.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
typedef enum { OP_LOAD_CONST = 255, OP_DECLARE, OP_LOAD_NULL, OP_JUMP } OperationType; typedef enum { OP_LOAD_CONST, OP_DECLARE, OP_LOAD_NULL, OP_LOAD_FUNCTION, OP_IDENTIFIER } OperationType;
typedef enum { TYPE_OP_STRING = 255, TYPE_OP_NUMBER } types; typedef enum { TYPE_OP_STRING, TYPE_OP_NUMBER } types;
typedef struct { typedef struct {
void *data; void *data;
size_t capacity; size_t capacity;
size_t size; size_t size;
struct hashmap * hashmap;
} ConstantArena; } ConstantArena;
typedef struct { typedef struct {
size_t registerCount; uint8_t registerCount;
DArray bytecode; DArray bytecode;
ConstantArena constants; ConstantArena constants;
} Translated; } Translated;
void arena_resize(ConstantArena *arena, size_t new_size);
void *arena_get(ConstantArena *arena, size_t offset); 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);
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); 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(); 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" "hello world"
"hello world" "hello world"
@@ -15,7 +24,10 @@
"hello world" "hello world"
"hello\u0000world" "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 1.24323234e2312324

View File

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

35
test.py Normal file
View File

@@ -0,0 +1,35 @@
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"}
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
if not first:
write('\n')
write(name)
first = False
if i>10000000:
break
i+=1
# Example usage:
max_width = 15
# sys.stdout.write("let ")
generate_names(max_width)

1
testing.ar Normal file
View File

@@ -0,0 +1 @@
let x = 10