vm + code split
This commit is contained in:
parent
50cd63aa38
commit
1af1fa5d16
2
Makefile
2
Makefile
@ -36,7 +36,7 @@ build_folder:
|
||||
mkdir $(BUILD_FOLDER) -p
|
||||
|
||||
compile_flags.txt:
|
||||
echo -xc $(CPP_FLAGS) | sed 's/\s\+/\n/g' > compile_flags.txt
|
||||
echo -xc $(C_FLAGS) | sed 's/\s\+/\n/g' > compile_flags.txt
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_FOLDER) compile_flags.txt
|
||||
|
179
src/allocator.c
Normal file
179
src/allocator.c
Normal file
@ -0,0 +1,179 @@
|
||||
#include "allocator.h"
|
||||
#include "panic.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
size_t align_size(size_t size)
|
||||
{
|
||||
const size_t word_size = sizeof(size_t);
|
||||
return (size + word_size) / word_size * word_size;
|
||||
}
|
||||
|
||||
void gc_buffer_construct(GCBuffer* buffer, size_t capacity)
|
||||
{
|
||||
void* data = malloc(capacity);
|
||||
ASSERT(buffer != NULL);
|
||||
*buffer = (GCBuffer) {
|
||||
.data = data,
|
||||
.index = 0,
|
||||
.capacity = capacity,
|
||||
};
|
||||
}
|
||||
|
||||
void gc_buffer_destroy(GCBuffer* buffer) { free(buffer->data); }
|
||||
|
||||
void gc_buffer_reset(GCBuffer* buffer) { buffer->index = 0; }
|
||||
|
||||
void* gc_buffer_alloc(GCBuffer* buffer, size_t size)
|
||||
{
|
||||
size_t aligned_size = align_size(size);
|
||||
if (buffer->capacity - buffer->index < aligned_size) {
|
||||
return NULL;
|
||||
}
|
||||
void* ptr = &((size_t*)buffer->data)[buffer->index];
|
||||
buffer->index += aligned_size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void gc_buffer_resize(GCBuffer* buffer, size_t minimum_capacity)
|
||||
{
|
||||
size_t aligned_min_cap = align_size(minimum_capacity);
|
||||
if (buffer->capacity >= aligned_min_cap) {
|
||||
return;
|
||||
}
|
||||
while (buffer->capacity < minimum_capacity) {
|
||||
buffer->capacity *= 2;
|
||||
}
|
||||
void* new_buffer = realloc(buffer->data, buffer->capacity);
|
||||
ASSERT(new_buffer);
|
||||
buffer->data = new_buffer;
|
||||
}
|
||||
|
||||
void gc_construct(GC* allocator, size_t start_capacity)
|
||||
{
|
||||
GCBuffer buffer_a;
|
||||
gc_buffer_construct(&buffer_a, start_capacity);
|
||||
GCBuffer buffer_b;
|
||||
gc_buffer_construct(&buffer_b, start_capacity);
|
||||
*allocator = (GC) {
|
||||
.alloc = gc_alloc,
|
||||
.realloc = gc_realloc,
|
||||
.buffer_a = buffer_a,
|
||||
.buffer_b = buffer_b,
|
||||
.select = GCBufferA,
|
||||
};
|
||||
}
|
||||
|
||||
bool gc_buffer_contains(GCBuffer* buffer, void* address)
|
||||
{
|
||||
return (size_t)address >= (size_t)buffer->data
|
||||
&& (size_t)address < (size_t)buffer->data + (size_t)buffer->index;
|
||||
}
|
||||
|
||||
void gc_destroy(GC* allocator)
|
||||
{
|
||||
gc_buffer_destroy(&allocator->buffer_a);
|
||||
gc_buffer_destroy(&allocator->buffer_b);
|
||||
}
|
||||
|
||||
void* gc_alloc(GC* allocator, size_t size)
|
||||
{
|
||||
size_t full_size = size + sizeof(size_t);
|
||||
GCBuffer* buffer = gc_selected_buffer(allocator);
|
||||
void* ptr = gc_buffer_alloc(buffer, full_size);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
size_t* alloc_size = (size_t*)ptr;
|
||||
*alloc_size = size;
|
||||
return &((size_t*)ptr)[1];
|
||||
}
|
||||
|
||||
void* gc_realloc(GC* allocator, void* data, size_t size)
|
||||
{
|
||||
size_t old_size = ((size_t*)data)[-1];
|
||||
void* new_ptr = gc_alloc(allocator, size);
|
||||
if (new_ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(new_ptr, (size_t*)data - sizeof(size_t), old_size + sizeof(size_t));
|
||||
size_t* size_ptr = (size_t*)new_ptr;
|
||||
*size_ptr = size;
|
||||
return &((size_t*)new_ptr)[1];
|
||||
}
|
||||
|
||||
void gc_collect(GC* allocator, void* entries, size_t entries_size)
|
||||
{
|
||||
gc_select_other(allocator);
|
||||
GCBuffer* source = gc_other_buffer(allocator);
|
||||
gc_relocate_branches_buffer(allocator, entries, entries_size);
|
||||
gc_buffer_reset(source);
|
||||
}
|
||||
|
||||
void gc_relocate_branches(GC* allocator, void* allocation)
|
||||
{
|
||||
size_t size = ((size_t*)allocation)[-1];
|
||||
gc_relocate_branches_buffer(allocator, allocation, size);
|
||||
}
|
||||
|
||||
void gc_relocate_branches_buffer(
|
||||
GC* allocator, void* branches, size_t branches_size
|
||||
)
|
||||
{
|
||||
GCBuffer* source = gc_other_buffer(allocator);
|
||||
for (size_t i = 0; i < branches_size; ++i) {
|
||||
if (gc_buffer_contains(source, &((size_t*)branches)[i])) {
|
||||
gc_relocate_allocation(allocator, branches);
|
||||
gc_relocate_branches(allocator, branches);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gc_relocate_allocation(GC* allocator, void* allocation)
|
||||
{
|
||||
GCBuffer* dest = gc_selected_buffer(allocator);
|
||||
void* ptr = &((size_t*)allocation)[-1];
|
||||
size_t size = ((size_t*)ptr)[0];
|
||||
size_t full_size = size + sizeof(size_t);
|
||||
void* new_ptr = gc_buffer_alloc(dest, full_size);
|
||||
if (new_ptr == NULL) {
|
||||
gc_buffer_resize(dest, dest->capacity + full_size);
|
||||
new_ptr = gc_buffer_alloc(dest, full_size);
|
||||
ASSERT(new_ptr != NULL);
|
||||
}
|
||||
size_t* selected_size_ptr = &((size_t*)new_ptr)[0];
|
||||
*selected_size_ptr = size;
|
||||
memcpy(&((size_t*)new_ptr)[1], allocation, size);
|
||||
}
|
||||
|
||||
GCBuffer* gc_selected_buffer(GC* allocator)
|
||||
{
|
||||
switch (allocator->select) {
|
||||
case GCBufferA:
|
||||
return &allocator->buffer_a;
|
||||
case GCBufferB:
|
||||
return &allocator->buffer_b;
|
||||
}
|
||||
}
|
||||
|
||||
GCBuffer* gc_other_buffer(GC* allocator)
|
||||
{
|
||||
switch (allocator->select) {
|
||||
case GCBufferA:
|
||||
return &allocator->buffer_b;
|
||||
case GCBufferB:
|
||||
return &allocator->buffer_a;
|
||||
}
|
||||
}
|
||||
|
||||
void gc_select_other(GC* allocator)
|
||||
{
|
||||
switch (allocator->select) {
|
||||
case GCBufferA:
|
||||
allocator->select = GCBufferB;
|
||||
break;
|
||||
case GCBufferB:
|
||||
allocator->select = GCBufferA;
|
||||
break;
|
||||
}
|
||||
}
|
57
src/allocator.h
Normal file
57
src/allocator.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef ALLOCATOR_H
|
||||
#define ALLOCATOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct Allocator Allocator;
|
||||
struct Allocator {
|
||||
void* (*alloc)(Allocator* allocator, size_t size);
|
||||
void* (*realloc)(Allocator* allocator, void* data, size_t size);
|
||||
};
|
||||
|
||||
size_t align_size(size_t size);
|
||||
|
||||
typedef struct {
|
||||
void* data;
|
||||
size_t index;
|
||||
size_t capacity;
|
||||
} GCBuffer;
|
||||
|
||||
void gc_buffer_construct(GCBuffer* buffer, size_t capacity);
|
||||
void gc_buffer_destroy(GCBuffer* buffer);
|
||||
void gc_buffer_reset(GCBuffer* buffer);
|
||||
void* gc_buffer_alloc(GCBuffer* buffer, size_t size);
|
||||
void gc_buffer_resize(GCBuffer* buffer, size_t minimum_capacity);
|
||||
bool gc_buffer_contains(GCBuffer* buffer, void* address);
|
||||
|
||||
typedef enum {
|
||||
GCBufferA,
|
||||
GCBufferB,
|
||||
} SelectedGCBuffer;
|
||||
|
||||
typedef struct GC GC;
|
||||
struct GC {
|
||||
void* (*alloc)(GC* allocator, size_t size);
|
||||
void* (*realloc)(GC* allocator, void* data, size_t size);
|
||||
GCBuffer buffer_a;
|
||||
GCBuffer buffer_b;
|
||||
SelectedGCBuffer select;
|
||||
};
|
||||
|
||||
void gc_construct(GC* allocator, size_t start_capacity);
|
||||
void gc_destroy(GC* allocator);
|
||||
void* gc_alloc(GC* allocator, size_t size);
|
||||
void* gc_realloc(GC* allocator, void* data, size_t size);
|
||||
void gc_collect(GC* allocator, void* entries, size_t entries_size);
|
||||
|
||||
void gc_relocate_branches(GC* allocator, void* allocation);
|
||||
void gc_relocate_branches_buffer(
|
||||
GC* allocator, void* branches, size_t branches_size
|
||||
);
|
||||
void gc_relocate_allocation(GC* allocator, void* allocation);
|
||||
GCBuffer* gc_selected_buffer(GC* allocator);
|
||||
GCBuffer* gc_other_buffer(GC* allocator);
|
||||
void gc_select_other(GC* allocator);
|
||||
|
||||
#endif
|
43
src/char_reader.c
Normal file
43
src/char_reader.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "char_reader.h"
|
||||
#include "panic.h"
|
||||
#include "vec.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void file_char_reader_construct(FileCharReader* reader, FILE* file)
|
||||
{
|
||||
*reader = (FileCharReader) {
|
||||
.next = file_char_reader_next,
|
||||
.value = file_char_reader_value,
|
||||
.file = file,
|
||||
.buffer = { 0 },
|
||||
};
|
||||
string_construct(&reader->buffer);
|
||||
}
|
||||
|
||||
void file_char_reader_destroy(FileCharReader* reader)
|
||||
{
|
||||
string_destroy(&reader->buffer);
|
||||
}
|
||||
|
||||
char file_char_reader_next(FileCharReader* reader)
|
||||
{
|
||||
int read_maybe_char = fgetc(reader->file);
|
||||
if (read_maybe_char == EOF) {
|
||||
return '\0';
|
||||
}
|
||||
char read_char = (char)read_maybe_char;
|
||||
string_append_char(&reader->buffer, read_char);
|
||||
return (char)read_char;
|
||||
}
|
||||
|
||||
StringSlice file_char_reader_value(
|
||||
const FileCharReader* reader, size_t index, size_t length
|
||||
)
|
||||
{
|
||||
ASSERT(index + length <= reader->buffer.length);
|
||||
return (StringSlice) {
|
||||
.data = &reader->buffer.data[index],
|
||||
.length = length,
|
||||
};
|
||||
}
|
31
src/char_reader.h
Normal file
31
src/char_reader.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef CHAR_READER_H
|
||||
#define CHAR_READER_H
|
||||
|
||||
#include "vec.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct CharReader CharReader;
|
||||
struct CharReader {
|
||||
char (*next)(CharReader* reader);
|
||||
StringSlice (*value)(const CharReader* reader, size_t index, size_t length);
|
||||
};
|
||||
|
||||
typedef struct FileCharReader FileCharReader;
|
||||
struct FileCharReader {
|
||||
char (*next)(FileCharReader* reader);
|
||||
StringSlice (*value)(
|
||||
const FileCharReader* reader, size_t index, size_t length
|
||||
);
|
||||
FILE* file;
|
||||
String buffer;
|
||||
};
|
||||
|
||||
void file_char_reader_construct(FileCharReader* reader, FILE* file);
|
||||
void file_char_reader_destroy(FileCharReader* reader);
|
||||
char file_char_reader_next(FileCharReader* reader);
|
||||
StringSlice file_char_reader_value(
|
||||
const FileCharReader* reader, size_t index, size_t length
|
||||
);
|
||||
|
||||
#endif
|
172
src/lexer.c
172
src/lexer.c
@ -1,180 +1,10 @@
|
||||
#include "lexer.h"
|
||||
#include "panic.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool string_slice_equal(StringSlice slice, const char* data)
|
||||
{
|
||||
if (strlen(data) != slice.length) {
|
||||
return false;
|
||||
}
|
||||
return strncmp(data, slice.data, slice.length) == 0;
|
||||
}
|
||||
|
||||
void string_construct(String* string)
|
||||
{
|
||||
*string = (String) {
|
||||
.data = NULL,
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void string_destroy(String* string)
|
||||
{
|
||||
if (string->data) {
|
||||
free(string->data);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t string_starting_alloc_size = 8;
|
||||
|
||||
void string_from_cstr(String* string, const char* value)
|
||||
{
|
||||
string_construct(string);
|
||||
string_append_cstr(string, value);
|
||||
}
|
||||
|
||||
void string_from_slice(String* string, StringSlice slice)
|
||||
{
|
||||
string_construct(string);
|
||||
for (size_t i = 0; i < slice.length; ++i) {
|
||||
string_append_char(string, slice.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void string_append(String* string, const String* value)
|
||||
{
|
||||
string_append_cstr(string, value->data);
|
||||
}
|
||||
|
||||
void string_append_char(String* string, char value)
|
||||
{
|
||||
if (string->length + 1 >= string->capacity) {
|
||||
if (string->capacity == 0) {
|
||||
string->capacity = string_starting_alloc_size;
|
||||
} else {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
if (string->data == NULL) {
|
||||
string->data = malloc(string->capacity * sizeof(char));
|
||||
ASSERT(string->data);
|
||||
} else {
|
||||
char* new_buffer
|
||||
= realloc(string->data, string->capacity * sizeof(char));
|
||||
ASSERT(new_buffer);
|
||||
string->data = new_buffer;
|
||||
}
|
||||
}
|
||||
string->data[string->length] = value;
|
||||
string->length += 1;
|
||||
string->data[string->length] = '\0';
|
||||
}
|
||||
|
||||
void string_append_cstr(String* string, const char* value)
|
||||
{
|
||||
size_t value_length = strlen(value);
|
||||
|
||||
if (string->length + value_length + 1 > string->capacity) {
|
||||
if (string->capacity == 0) {
|
||||
string->capacity = string_starting_alloc_size;
|
||||
}
|
||||
while (string->length + value_length + 1 > string->capacity) {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
char* new_buffer
|
||||
= realloc(string->data, string->capacity * sizeof(char));
|
||||
ASSERT(new_buffer);
|
||||
string->data = new_buffer;
|
||||
}
|
||||
|
||||
memcpy(&string->data[string->length], value, value_length);
|
||||
string->length += value_length;
|
||||
string->data[string->length] = '\0';
|
||||
}
|
||||
|
||||
void string_append_format(String* string, const char* format, ...)
|
||||
{
|
||||
va_list varargs;
|
||||
va_start(varargs, format);
|
||||
|
||||
size_t format_length = (size_t)vsnprintf(NULL, 0, format, varargs);
|
||||
|
||||
va_end(varargs);
|
||||
|
||||
va_start(varargs, format);
|
||||
|
||||
if (string->length + format_length + 1 > string->capacity) {
|
||||
if (string->capacity == 0) {
|
||||
string->capacity = string_starting_alloc_size;
|
||||
} else {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
while (string->length + format_length + 1 > string->capacity) {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
char* new_buffer
|
||||
= realloc(string->data, string->capacity * sizeof(char));
|
||||
ASSERT(new_buffer);
|
||||
string->data = new_buffer;
|
||||
}
|
||||
|
||||
size_t written = (size_t)vsnprintf(
|
||||
&string->data[string->length],
|
||||
string->capacity - string->length,
|
||||
format,
|
||||
varargs
|
||||
);
|
||||
string->length += written;
|
||||
string->data[string->length] = '\0';
|
||||
|
||||
va_end(varargs);
|
||||
}
|
||||
|
||||
bool string_equal(const String* string, const char* value)
|
||||
{
|
||||
return strncmp(value, string->data, string->length + 1);
|
||||
}
|
||||
|
||||
void file_char_reader_construct(FileCharReader* reader, FILE* file)
|
||||
{
|
||||
*reader = (FileCharReader) {
|
||||
.next = file_char_reader_next,
|
||||
.value = file_char_reader_value,
|
||||
.file = file,
|
||||
.buffer = { 0 },
|
||||
};
|
||||
string_construct(&reader->buffer);
|
||||
}
|
||||
|
||||
void file_char_reader_destroy(FileCharReader* reader)
|
||||
{
|
||||
string_destroy(&reader->buffer);
|
||||
}
|
||||
|
||||
char file_char_reader_next(FileCharReader* reader)
|
||||
{
|
||||
int read_maybe_char = fgetc(reader->file);
|
||||
if (read_maybe_char == EOF) {
|
||||
return '\0';
|
||||
}
|
||||
char read_char = (char)read_maybe_char;
|
||||
string_append_char(&reader->buffer, read_char);
|
||||
return (char)read_char;
|
||||
}
|
||||
|
||||
StringSlice file_char_reader_value(
|
||||
const FileCharReader* reader, size_t index, size_t length
|
||||
)
|
||||
{
|
||||
ASSERT(index + length <= reader->buffer.length);
|
||||
return (StringSlice) {
|
||||
.data = &reader->buffer.data[index],
|
||||
.length = length,
|
||||
};
|
||||
}
|
||||
|
||||
void error_construct(Error* error, Pos pos, String message)
|
||||
{
|
||||
*error = (Error) {
|
||||
|
70
src/lexer.h
70
src/lexer.h
@ -1,79 +1,13 @@
|
||||
#ifndef LEXER_H
|
||||
#define LEXER_H
|
||||
|
||||
#include "char_reader.h"
|
||||
#include "vec.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PANIC(...) \
|
||||
(fprintf(stderr, "panic: "), \
|
||||
fprintf(stderr, __VA_ARGS__), \
|
||||
fprintf(stderr, ", at %s:%d in %s()\n", __FILE__, __LINE__, __func__), \
|
||||
exit(1));
|
||||
|
||||
#define ASSERT(CONDITION) \
|
||||
{ \
|
||||
if (!(CONDITION)) { \
|
||||
(fprintf(stderr, "assertion failed: "), \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
"(%s), at %s:%d in %s()\n", \
|
||||
#CONDITION, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
__func__ \
|
||||
), \
|
||||
exit(1)); \
|
||||
} \
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* data;
|
||||
size_t length;
|
||||
} StringSlice;
|
||||
|
||||
bool string_slice_equal(StringSlice slice, const char* data);
|
||||
|
||||
typedef struct {
|
||||
char* data;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
} String;
|
||||
|
||||
void string_construct(String* string);
|
||||
void string_destroy(String* string);
|
||||
void string_from_cstr(String* string, const char* value);
|
||||
void string_from_slice(String* string, StringSlice slice);
|
||||
void string_append(String* string, const String* value);
|
||||
void string_append_char(String* string, char value);
|
||||
void string_append_cstr(String* string, const char* value);
|
||||
void string_append_format(String* string, const char* format, ...);
|
||||
bool string_equal(const String* string, const char* value);
|
||||
|
||||
typedef struct CharReader CharReader;
|
||||
struct CharReader {
|
||||
char (*next)(CharReader* reader);
|
||||
StringSlice (*value)(const CharReader* reader, size_t index, size_t length);
|
||||
};
|
||||
|
||||
typedef struct FileCharReader FileCharReader;
|
||||
struct FileCharReader {
|
||||
char (*next)(FileCharReader* reader);
|
||||
StringSlice (*value)(
|
||||
const FileCharReader* reader, size_t index, size_t length
|
||||
);
|
||||
FILE* file;
|
||||
String buffer;
|
||||
};
|
||||
|
||||
void file_char_reader_construct(FileCharReader* reader, FILE* file);
|
||||
void file_char_reader_destroy(FileCharReader* reader);
|
||||
char file_char_reader_next(FileCharReader* reader);
|
||||
StringSlice file_char_reader_value(
|
||||
const FileCharReader* reader, size_t index, size_t length
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
size_t index;
|
||||
size_t line;
|
||||
|
29
src/panic.h
Normal file
29
src/panic.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef PANIC_H
|
||||
#define PANIC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PANIC(...) \
|
||||
(fprintf(stderr, "panic: "), \
|
||||
fprintf(stderr, __VA_ARGS__), \
|
||||
fprintf(stderr, ", at %s:%d in %s()\n", __FILE__, __LINE__, __func__), \
|
||||
exit(1));
|
||||
|
||||
#define ASSERT(CONDITION) \
|
||||
{ \
|
||||
if (!(CONDITION)) { \
|
||||
(fprintf(stderr, "assertion failed: "), \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
"(%s), at %s:%d in %s()\n", \
|
||||
#CONDITION, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
__func__ \
|
||||
), \
|
||||
exit(1)); \
|
||||
} \
|
||||
};
|
||||
|
||||
#endif
|
27
src/parser.c
27
src/parser.c
@ -1,5 +1,6 @@
|
||||
#include "parser.h"
|
||||
#include "lexer.h"
|
||||
#include "panic.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -7,29 +8,29 @@ void expr_vec_construct(ExprVec* vec)
|
||||
{
|
||||
const size_t starting_capacity = 8;
|
||||
*vec = (ExprVec) {
|
||||
.exprs = malloc(starting_capacity * sizeof(Expr)),
|
||||
.data = malloc(starting_capacity * sizeof(Expr)),
|
||||
.length = 0,
|
||||
.capacity = starting_capacity,
|
||||
};
|
||||
ASSERT(vec->exprs);
|
||||
ASSERT(vec->data);
|
||||
}
|
||||
void expr_vec_destroy(ExprVec* vec)
|
||||
{
|
||||
for (size_t i = 0; i < vec->length; ++i) {
|
||||
expr_destroy(&vec->exprs[i]);
|
||||
expr_destroy(&vec->data[i]);
|
||||
}
|
||||
free(vec->exprs);
|
||||
free(vec->data);
|
||||
}
|
||||
|
||||
void expr_vec_push(ExprVec* vec, Expr expr)
|
||||
{
|
||||
if (vec->length >= vec->capacity) {
|
||||
vec->capacity *= 2;
|
||||
Expr* new_buffer = realloc(vec->exprs, vec->capacity * sizeof(Expr));
|
||||
Expr* new_buffer = realloc(vec->data, vec->capacity * sizeof(Expr));
|
||||
ASSERT(new_buffer);
|
||||
vec->exprs = new_buffer;
|
||||
vec->data = new_buffer;
|
||||
}
|
||||
vec->exprs[vec->length] = expr;
|
||||
vec->data[vec->length] = expr;
|
||||
vec->length += 1;
|
||||
}
|
||||
|
||||
@ -37,10 +38,10 @@ void expr_vec_stringify(const ExprVec* vec, String* acc)
|
||||
{
|
||||
string_append_cstr(acc, "[");
|
||||
if (vec->length > 0) {
|
||||
expr_stringify(&vec->exprs[0], acc);
|
||||
expr_stringify(&vec->data[0], acc);
|
||||
for (size_t i = 1; i < vec->length; ++i) {
|
||||
string_append_cstr(acc, ", ");
|
||||
expr_stringify(&vec->exprs[i], acc);
|
||||
expr_stringify(&vec->data[i], acc);
|
||||
}
|
||||
}
|
||||
string_append_cstr(acc, "]");
|
||||
@ -125,10 +126,10 @@ void expr_stringify(const Expr* expr, String* acc)
|
||||
case ExprTypeList:
|
||||
string_append_cstr(acc, "[");
|
||||
if (expr->list.length > 0) {
|
||||
expr_stringify(&expr->list.exprs[0], acc);
|
||||
expr_stringify(&expr->list.data[0], acc);
|
||||
for (size_t i = 1; i < expr->list.length; ++i) {
|
||||
string_append_cstr(acc, " ");
|
||||
expr_stringify(&expr->list.exprs[i], acc);
|
||||
expr_stringify(&expr->list.data[i], acc);
|
||||
}
|
||||
}
|
||||
string_append_cstr(acc, "]");
|
||||
@ -136,10 +137,10 @@ void expr_stringify(const Expr* expr, String* acc)
|
||||
case ExprTypeS:
|
||||
string_append_cstr(acc, "(");
|
||||
if (expr->s.length > 0) {
|
||||
expr_stringify(&expr->s.exprs[0], acc);
|
||||
expr_stringify(&expr->s.data[0], acc);
|
||||
for (size_t i = 1; i < expr->s.length; ++i) {
|
||||
string_append_cstr(acc, " ");
|
||||
expr_stringify(&expr->s.exprs[i], acc);
|
||||
expr_stringify(&expr->s.data[i], acc);
|
||||
}
|
||||
}
|
||||
string_append_cstr(acc, ")");
|
||||
|
@ -19,7 +19,7 @@ typedef enum {
|
||||
typedef struct Expr Expr;
|
||||
|
||||
typedef struct {
|
||||
Expr* exprs;
|
||||
Expr* data;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
} ExprVec;
|
||||
|
115
src/runtime.c
115
src/runtime.c
@ -1,5 +1,8 @@
|
||||
#include "runtime.h"
|
||||
#include "lexer.h"
|
||||
#include "panic.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -27,7 +30,7 @@ Value* value_vec_at(const ValueVec* vec, int64_t index)
|
||||
if (index < 0) {
|
||||
return value_vec_at(vec, -index);
|
||||
}
|
||||
if (index >= vec->length) {
|
||||
if (index >= (int64_t)vec->length) {
|
||||
return NULL;
|
||||
}
|
||||
return &vec->data[index];
|
||||
@ -135,117 +138,13 @@ void value_stringify(const Value* value, String* acc)
|
||||
}
|
||||
}
|
||||
|
||||
void gc_buffer_construct(GCBuffer* buffer, size_t capacity)
|
||||
{
|
||||
void* data = malloc(capacity);
|
||||
ASSERT(buffer != NULL);
|
||||
*buffer = (GCBuffer) {
|
||||
.data = data,
|
||||
.capacity = capacity,
|
||||
};
|
||||
}
|
||||
|
||||
void gc_buffer_destroy(GCBuffer* buffer) { free(buffer->data); }
|
||||
|
||||
void gc_buffer_resize(GCBuffer* buffer, size_t minimum_capacity)
|
||||
{
|
||||
if (buffer->capacity >= minimum_capacity) {
|
||||
return;
|
||||
}
|
||||
while (buffer->capacity < minimum_capacity) {
|
||||
buffer->capacity *= 2;
|
||||
}
|
||||
void* new_buffer = realloc(buffer->data, buffer->capacity);
|
||||
ASSERT(new_buffer);
|
||||
buffer->data = new_buffer;
|
||||
}
|
||||
|
||||
void gc_construct(GC* allocator, size_t start_capacity)
|
||||
{
|
||||
GCBuffer buffer_a;
|
||||
gc_buffer_construct(&buffer_a, start_capacity);
|
||||
GCBuffer buffer_b;
|
||||
gc_buffer_construct(&buffer_b, start_capacity);
|
||||
*allocator = (GC) {
|
||||
.alloc = gc_alloc,
|
||||
.realloc = gc_realloc,
|
||||
.buffer_a = buffer_a,
|
||||
.buffer_b = buffer_b,
|
||||
.select = GCBufferA,
|
||||
.index = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void gc_destroy(GC* allocator)
|
||||
{
|
||||
gc_buffer_destroy(&allocator->buffer_a);
|
||||
gc_buffer_destroy(&allocator->buffer_b);
|
||||
}
|
||||
|
||||
void* gc_alloc(GC* allocator, size_t size)
|
||||
{
|
||||
GCBuffer* buffer = gc_selected_buffer(allocator);
|
||||
if (buffer->capacity < allocator->index + size) {
|
||||
return NULL;
|
||||
}
|
||||
void* ptr = &buffer->data[allocator->index];
|
||||
allocator->index += size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* gc_realloc(GC* allocator, void* data, size_t size)
|
||||
{
|
||||
void* new_ptr = gc_alloc(allocator, size);
|
||||
if (new_ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(new_ptr, data, size);
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void* gc_collect(GC* allocator, ValueVec* stack, size_t to_be_allocated)
|
||||
{
|
||||
GCBuffer* selected = gc_selected_buffer(allocator);
|
||||
GCBuffer* other = gc_other_buffer(allocator);
|
||||
}
|
||||
|
||||
GCBuffer* gc_selected_buffer(GC* allocator)
|
||||
{
|
||||
switch (allocator->select) {
|
||||
case GCBufferA:
|
||||
return &allocator->buffer_a;
|
||||
case GCBufferB:
|
||||
return &allocator->buffer_b;
|
||||
}
|
||||
}
|
||||
|
||||
GCBuffer* gc_other_buffer(GC* allocator)
|
||||
{
|
||||
switch (allocator->select) {
|
||||
case GCBufferA:
|
||||
return &allocator->buffer_b;
|
||||
case GCBufferB:
|
||||
return &allocator->buffer_a;
|
||||
}
|
||||
}
|
||||
|
||||
void gc_select_other(GC* allocator)
|
||||
{
|
||||
switch (allocator->select) {
|
||||
case GCBufferA:
|
||||
allocator->select = GCBufferB;
|
||||
break;
|
||||
case GCBufferB:
|
||||
allocator->select = GCBufferA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void runtime_construct(Runtime* runtime, Allocator* allocator)
|
||||
{
|
||||
*runtime = (Runtime) {
|
||||
.allocator = allocator,
|
||||
.stack = { 0 },
|
||||
};
|
||||
value_vec_construct(&runtime->stack, allocator);
|
||||
}
|
||||
|
||||
void runtime_destroy(Runtime* runtime) { }
|
||||
void runtime_destroy(Runtime* runtime) { value_vec_destroy(&runtime->stack); }
|
||||
|
@ -1,16 +1,11 @@
|
||||
#ifndef RUNTIME_H
|
||||
#define RUNTIME_H
|
||||
|
||||
#include "allocator.h"
|
||||
#include "lexer.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct Allocator Allocator;
|
||||
struct Allocator {
|
||||
void* (*alloc)(Allocator* allocator, size_t size);
|
||||
void* (*realloc)(Allocator* allocator, void* data, size_t size);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
ValueTypeSymbol,
|
||||
ValueTypeInt,
|
||||
@ -52,42 +47,9 @@ struct Value {
|
||||
void value_destroy(Value* value);
|
||||
void value_stringify(const Value* value, String* acc);
|
||||
|
||||
typedef struct {
|
||||
void* data;
|
||||
size_t capacity;
|
||||
} GCBuffer;
|
||||
|
||||
void gc_buffer_construct(GCBuffer* buffer, size_t capacity);
|
||||
void gc_buffer_destroy(GCBuffer* buffer);
|
||||
void gc_buffer_resize(GCBuffer* buffer, size_t minimum_capacity);
|
||||
|
||||
typedef enum {
|
||||
GCBufferA,
|
||||
GCBufferB,
|
||||
} SelectedGCBuffer;
|
||||
|
||||
typedef struct GC GC;
|
||||
struct GC {
|
||||
void* (*alloc)(GC* allocator, size_t size);
|
||||
void* (*realloc)(GC* allocator, void* data, size_t size);
|
||||
GCBuffer buffer_a;
|
||||
GCBuffer buffer_b;
|
||||
SelectedGCBuffer select;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
void gc_construct(GC* allocator, size_t start_capacity);
|
||||
void gc_destroy(GC* allocator);
|
||||
void* gc_alloc(GC* allocator, size_t size);
|
||||
void* gc_realloc(GC* allocator, void* data, size_t size);
|
||||
void* gc_collect(GC* allocator, ValueVec* stack, size_t to_be_allocated);
|
||||
|
||||
GCBuffer* gc_selected_buffer(GC* allocator);
|
||||
GCBuffer* gc_other_buffer(GC* allocator);
|
||||
void gc_select_other(GC* allocator);
|
||||
|
||||
typedef struct {
|
||||
Allocator* allocator;
|
||||
ValueVec stack;
|
||||
} Runtime;
|
||||
|
||||
void runtime_construct(Runtime* runtime, Allocator* allocator);
|
||||
|
138
src/vec.c
Normal file
138
src/vec.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include "vec.h"
|
||||
#include "panic.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool string_slice_equal(StringSlice slice, const char* data)
|
||||
{
|
||||
if (strlen(data) != slice.length) {
|
||||
return false;
|
||||
}
|
||||
return strncmp(data, slice.data, slice.length) == 0;
|
||||
}
|
||||
|
||||
void string_construct(String* string)
|
||||
{
|
||||
*string = (String) {
|
||||
.data = NULL,
|
||||
.length = 0,
|
||||
.capacity = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void string_destroy(String* string)
|
||||
{
|
||||
if (string->data) {
|
||||
free(string->data);
|
||||
}
|
||||
}
|
||||
|
||||
const size_t string_starting_alloc_size = 8;
|
||||
|
||||
void string_from_cstr(String* string, const char* value)
|
||||
{
|
||||
string_construct(string);
|
||||
string_append_cstr(string, value);
|
||||
}
|
||||
|
||||
void string_from_slice(String* string, StringSlice slice)
|
||||
{
|
||||
string_construct(string);
|
||||
for (size_t i = 0; i < slice.length; ++i) {
|
||||
string_append_char(string, slice.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void string_append(String* string, const String* value)
|
||||
{
|
||||
string_append_cstr(string, value->data);
|
||||
}
|
||||
|
||||
void string_append_char(String* string, char value)
|
||||
{
|
||||
if (string->length + 1 >= string->capacity) {
|
||||
if (string->capacity == 0) {
|
||||
string->capacity = string_starting_alloc_size;
|
||||
} else {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
if (string->data == NULL) {
|
||||
string->data = malloc(string->capacity * sizeof(char));
|
||||
ASSERT(string->data);
|
||||
} else {
|
||||
char* new_buffer
|
||||
= realloc(string->data, string->capacity * sizeof(char));
|
||||
ASSERT(new_buffer);
|
||||
string->data = new_buffer;
|
||||
}
|
||||
}
|
||||
string->data[string->length] = value;
|
||||
string->length += 1;
|
||||
string->data[string->length] = '\0';
|
||||
}
|
||||
|
||||
void string_append_cstr(String* string, const char* value)
|
||||
{
|
||||
size_t value_length = strlen(value);
|
||||
|
||||
if (string->length + value_length + 1 > string->capacity) {
|
||||
if (string->capacity == 0) {
|
||||
string->capacity = string_starting_alloc_size;
|
||||
}
|
||||
while (string->length + value_length + 1 > string->capacity) {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
char* new_buffer
|
||||
= realloc(string->data, string->capacity * sizeof(char));
|
||||
ASSERT(new_buffer);
|
||||
string->data = new_buffer;
|
||||
}
|
||||
|
||||
memcpy(&string->data[string->length], value, value_length);
|
||||
string->length += value_length;
|
||||
string->data[string->length] = '\0';
|
||||
}
|
||||
|
||||
void string_append_format(String* string, const char* format, ...)
|
||||
{
|
||||
va_list varargs;
|
||||
va_start(varargs, format);
|
||||
|
||||
size_t format_length = (size_t)vsnprintf(NULL, 0, format, varargs);
|
||||
|
||||
va_end(varargs);
|
||||
|
||||
va_start(varargs, format);
|
||||
|
||||
if (string->length + format_length + 1 > string->capacity) {
|
||||
if (string->capacity == 0) {
|
||||
string->capacity = string_starting_alloc_size;
|
||||
} else {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
while (string->length + format_length + 1 > string->capacity) {
|
||||
string->capacity *= 2;
|
||||
}
|
||||
char* new_buffer
|
||||
= realloc(string->data, string->capacity * sizeof(char));
|
||||
ASSERT(new_buffer);
|
||||
string->data = new_buffer;
|
||||
}
|
||||
|
||||
size_t written = (size_t)vsnprintf(
|
||||
&string->data[string->length],
|
||||
string->capacity - string->length,
|
||||
format,
|
||||
varargs
|
||||
);
|
||||
string->length += written;
|
||||
string->data[string->length] = '\0';
|
||||
|
||||
va_end(varargs);
|
||||
}
|
||||
|
||||
bool string_equal(const String* string, const char* value)
|
||||
{
|
||||
return strncmp(value, string->data, string->length + 1);
|
||||
}
|
30
src/vec.h
Normal file
30
src/vec.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef VEC_H
|
||||
#define VEC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
const char* data;
|
||||
size_t length;
|
||||
} StringSlice;
|
||||
|
||||
bool string_slice_equal(StringSlice slice, const char* data);
|
||||
|
||||
typedef struct {
|
||||
char* data;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
} String;
|
||||
|
||||
void string_construct(String* string);
|
||||
void string_destroy(String* string);
|
||||
void string_from_cstr(String* string, const char* value);
|
||||
void string_from_slice(String* string, StringSlice slice);
|
||||
void string_append(String* string, const String* value);
|
||||
void string_append_char(String* string, char value);
|
||||
void string_append_cstr(String* string, const char* value);
|
||||
void string_append_format(String* string, const char* format, ...);
|
||||
bool string_equal(const String* string, const char* value);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user