Compare commits
4 Commits
7df292ed9e
...
042cc48e8c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
042cc48e8c | ||
|
|
b51aaa3d65 | ||
|
|
6499a9dd6d | ||
|
|
c1cdb8607d |
@@ -14,7 +14,6 @@
|
||||
#include <alisp/stream.h>
|
||||
#include <alisp/sv.h>
|
||||
#include <alisp/symtable.h>
|
||||
#include <alisp/tag.h>
|
||||
#include <alisp/vec.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,15 +23,65 @@ typedef struct
|
||||
lisp_t *car, *cdr;
|
||||
} cons_t;
|
||||
|
||||
/// Tagging system
|
||||
typedef enum Tag
|
||||
{
|
||||
TAG_NIL = 0b00000000, // Start of atomic types
|
||||
TAG_INT = 0b00000001, // Special tag so we can encode 63 bit integers
|
||||
TAG_SYM = 0b00000100,
|
||||
TAG_CONS = 0b00000010, // Start of container types
|
||||
TAG_VEC = 0b00000110,
|
||||
NUM_TAGS = 5,
|
||||
} tag_t;
|
||||
|
||||
static_assert(NUM_TAGS == 5, "Expected NUM_TAGS == 5 for enum SHIFT");
|
||||
enum Shift
|
||||
{
|
||||
SHIFT_INT = 1,
|
||||
SHIFT_SYM = 8,
|
||||
SHIFT_CONS = 8,
|
||||
SHIFT_VEC = 8,
|
||||
};
|
||||
|
||||
static_assert(NUM_TAGS == 5, "Expected NUM_TAGS == 5 for enum MASK");
|
||||
enum Mask
|
||||
{
|
||||
MASK_INT = 0b00000001,
|
||||
MASK_SYM = 0b11111111,
|
||||
MASK_CONS = 0b11111111,
|
||||
MASK_VEC = 0b11111111,
|
||||
};
|
||||
|
||||
// Some helper macros for tagging
|
||||
#define TAG(PTR, TYPE) ((lisp_t *)(((PTR) << SHIFT_##TYPE) | TAG_##TYPE))
|
||||
#define IS_TAG(PTR, TYPE) (((u64)(PTR) & MASK_##TYPE) == TAG_##TYPE)
|
||||
#define UNTAG(PTR, TYPE) (((u64)PTR) >> SHIFT_##TYPE)
|
||||
|
||||
#define INT_MAX ((((i64)1) << 62) - 1)
|
||||
#define INT_MIN (-(((i64)1) << 62))
|
||||
|
||||
tag_t get_tag(const lisp_t *);
|
||||
lisp_t *tag_int(const i64);
|
||||
lisp_t *tag_sym(const char *);
|
||||
lisp_t *tag_cons(const cons_t *);
|
||||
lisp_t *tag_vec(const vec_t *);
|
||||
|
||||
/// System context
|
||||
typedef struct
|
||||
{
|
||||
vec_t memory;
|
||||
vec_t conses;
|
||||
vec_t vectors;
|
||||
u64 num_conses, num_vectors;
|
||||
} sys_mem_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sys_mem_t memory;
|
||||
sym_table_t symtable;
|
||||
} sys_t;
|
||||
|
||||
void sys_init(sys_t *);
|
||||
void sys_register(sys_t *, lisp_t *);
|
||||
lisp_t *sys_alloc(sys_t *, tag_t type);
|
||||
void sys_free(sys_t *);
|
||||
|
||||
// Debugging function: provides total memory usage from system.
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/* tag.h: Pointer tagging
|
||||
* Created: 2026-02-04
|
||||
* Author: Aryadev Chavali
|
||||
* License: See end of file
|
||||
* Commentary:
|
||||
*/
|
||||
|
||||
#ifndef TAG_H
|
||||
#define TAG_H
|
||||
|
||||
#include <alisp/lisp.h>
|
||||
|
||||
typedef enum Tag
|
||||
{
|
||||
TAG_NIL = 0b00000000, // Start of atomic types
|
||||
TAG_INT = 0b00000001, // Special tag so we can encode 63 bit integers
|
||||
TAG_SYM = 0b00000100,
|
||||
TAG_CONS = 0b00000010, // Start of container types
|
||||
TAG_VEC = 0b00000110,
|
||||
NUM_TAGS = 5,
|
||||
} tag_t;
|
||||
|
||||
static_assert(NUM_TAGS == 5, "Expected NUM_TAGS == 5 for enum SHIFT");
|
||||
enum Shift
|
||||
{
|
||||
SHIFT_INT = 1,
|
||||
SHIFT_SYM = 8,
|
||||
SHIFT_CONS = 8,
|
||||
SHIFT_VEC = 8,
|
||||
};
|
||||
|
||||
static_assert(NUM_TAGS == 5, "Expected NUM_TAGS == 5 for enum MASK");
|
||||
enum Mask
|
||||
{
|
||||
MASK_INT = 0b00000001,
|
||||
MASK_SYM = 0b11111111,
|
||||
MASK_CONS = 0b11111111,
|
||||
MASK_VEC = 0b11111111,
|
||||
};
|
||||
|
||||
// Some helper macros for tagging
|
||||
#define TAG(PTR, TYPE) ((lisp_t *)(((PTR) << SHIFT_##TYPE) | TAG_##TYPE))
|
||||
#define IS_TAG(PTR, TYPE) (((u64)(PTR) & MASK_##TYPE) == TAG_##TYPE)
|
||||
#define UNTAG(PTR, TYPE) (((u64)PTR) >> SHIFT_##TYPE)
|
||||
|
||||
#define INT_MAX ((((i64)1) << 62) - 1)
|
||||
#define INT_MIN (-(((i64)1) << 62))
|
||||
|
||||
tag_t get_tag(const lisp_t *);
|
||||
lisp_t *tag_int(const i64);
|
||||
lisp_t *tag_sym(const char *);
|
||||
lisp_t *tag_cons(const cons_t *);
|
||||
lisp_t *tag_vec(const vec_t *);
|
||||
|
||||
#endif
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for
|
||||
* details.
|
||||
|
||||
* You may distribute and modify this code under the terms of the GNU General
|
||||
* Public License Version 2, which you should have received a copy of along with
|
||||
* this program. If not, please go to <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
79
src/lisp.c
79
src/lisp.c
@@ -9,41 +9,75 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <alisp/lisp.h>
|
||||
#include <alisp/tag.h>
|
||||
|
||||
void sys_init(sys_t *sys)
|
||||
{
|
||||
memset(sys, 0, sizeof(*sys));
|
||||
}
|
||||
|
||||
void sys_register(sys_t *sys, lisp_t *ptr)
|
||||
lisp_t *sys_alloc(sys_t *sys, tag_t type)
|
||||
{
|
||||
// Simply append it to the list of currently active conses
|
||||
vec_append(&sys->memory, &ptr, sizeof(&ptr));
|
||||
switch (type)
|
||||
{
|
||||
case TAG_CONS:
|
||||
{
|
||||
cons_t *cons = calloc(1, sizeof(*cons));
|
||||
lisp_t *lisp = tag_cons(cons);
|
||||
vec_append(&sys->memory.conses, &lisp, sizeof(&lisp));
|
||||
sys->memory.num_conses++;
|
||||
return lisp;
|
||||
}
|
||||
case TAG_VEC:
|
||||
{
|
||||
vec_t *vec = calloc(1, sizeof(*vec));
|
||||
lisp_t *lisp = tag_vec(vec);
|
||||
vec_append(&sys->memory.vectors, &lisp, sizeof(&lisp));
|
||||
sys->memory.num_vectors++;
|
||||
return lisp;
|
||||
}
|
||||
// Shouldn't be registered
|
||||
case TAG_NIL:
|
||||
case TAG_INT:
|
||||
case TAG_SYM:
|
||||
default:
|
||||
FAIL("Unreachable");
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
u64 sys_cost(sys_t *sys)
|
||||
{
|
||||
return sym_table_cost(&sys->symtable) + sys->memory.capacity;
|
||||
u64 vec_capacity = 0;
|
||||
for (u64 i = 0; i < sys->memory.num_vectors; ++i)
|
||||
{
|
||||
lisp_t *vec = VEC_GET(&sys->memory.vectors, i, lisp_t *);
|
||||
vec_capacity += as_vec(vec)->capacity;
|
||||
}
|
||||
return sym_table_cost(&sys->symtable) +
|
||||
(sys->memory.num_conses * sizeof(cons_t)) + vec_capacity;
|
||||
}
|
||||
|
||||
void sys_free(sys_t *sys)
|
||||
{
|
||||
static_assert(NUM_TAGS == 5);
|
||||
|
||||
sym_table_free(&sys->symtable);
|
||||
if (sys->memory.size == 0)
|
||||
return;
|
||||
|
||||
// Iterate through each cell of memory currently allocated and free them
|
||||
for (size_t i = 0; i < VEC_SIZE(&sys->memory, lisp_t **); ++i)
|
||||
for (size_t i = 0; i < VEC_SIZE(&sys->memory.conses, lisp_t **); ++i)
|
||||
{
|
||||
lisp_t *allocated = VEC_GET(&sys->memory, i, lisp_t *);
|
||||
lisp_t *allocated = VEC_GET(&sys->memory.conses, i, lisp_t *);
|
||||
lisp_free(allocated);
|
||||
}
|
||||
|
||||
// Free the container
|
||||
vec_free(&sys->memory);
|
||||
// Iterate through each cell of memory currently allocated and free them
|
||||
for (size_t i = 0; i < VEC_SIZE(&sys->memory.vectors, lisp_t **); ++i)
|
||||
{
|
||||
lisp_t *allocated = VEC_GET(&sys->memory.vectors, i, lisp_t *);
|
||||
lisp_free(allocated);
|
||||
}
|
||||
|
||||
// Free the containers
|
||||
vec_free(&sys->memory.conses);
|
||||
vec_free(&sys->memory.vectors);
|
||||
|
||||
// Ensure no one treats this as active in any sense
|
||||
memset(sys, 0, sizeof(*sys));
|
||||
@@ -56,22 +90,17 @@ lisp_t *make_int(i64 i)
|
||||
|
||||
lisp_t *cons(sys_t *sys, lisp_t *car, lisp_t *cdr)
|
||||
{
|
||||
cons_t *cons = calloc(1, sizeof(*cons));
|
||||
cons->car = car;
|
||||
cons->cdr = cdr;
|
||||
|
||||
lisp_t *lcons = tag_cons(cons);
|
||||
sys_register(sys, lcons);
|
||||
return lcons;
|
||||
lisp_t *cons = sys_alloc(sys, TAG_CONS);
|
||||
CAR(cons) = car;
|
||||
CDR(cons) = cdr;
|
||||
return cons;
|
||||
}
|
||||
|
||||
lisp_t *make_vec(sys_t *sys, u64 capacity)
|
||||
{
|
||||
vec_t *vec = calloc(1, sizeof(*vec));
|
||||
vec_init(vec, capacity);
|
||||
lisp_t *ptr = tag_vec(vec);
|
||||
sys_register(sys, ptr);
|
||||
return ptr;
|
||||
lisp_t *vec = sys_alloc(sys, TAG_VEC);
|
||||
vec_init(as_vec(vec), capacity);
|
||||
return vec;
|
||||
}
|
||||
|
||||
lisp_t *intern(sys_t *sys, sv_t sv)
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <alisp/reader.h>
|
||||
#include <alisp/tag.h>
|
||||
|
||||
const char *read_err_to_cstr(read_err_t err)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <alisp/tag.h>
|
||||
#include <alisp/lisp.h>
|
||||
|
||||
lisp_t *tag_int(i64 i)
|
||||
{
|
||||
|
||||
@@ -151,44 +151,42 @@ void sys_test(void)
|
||||
TEST_START();
|
||||
sys_t sys = {0};
|
||||
sys_init(&sys);
|
||||
u64 old_memory_size = sys.memory.size;
|
||||
u64 old_memory_size = sys_cost(&sys);
|
||||
|
||||
// Creating integers doesn't affect memory size
|
||||
(void)make_int(2000);
|
||||
TEST(sys.memory.size == old_memory_size,
|
||||
TEST(sys_cost(&sys) == old_memory_size,
|
||||
"Making integers doesn't affect system memory size");
|
||||
|
||||
// Creating symbols won't affect memory size, but does affect the symbol table
|
||||
// Creating symbols does affect memory size and memory table
|
||||
(void)intern(&sys, SV_AUTO("hello world!"));
|
||||
TEST(sys.memory.size == old_memory_size,
|
||||
TEST(sys_cost(&sys) > old_memory_size,
|
||||
"Interning doesn't affect system memory size");
|
||||
TEST(sys.symtable.count > 0, "Interning affects symbol table");
|
||||
old_memory_size = sys_cost(&sys);
|
||||
|
||||
// Creating conses do affect memory size
|
||||
(void)cons(&sys, make_int(1), make_int(2));
|
||||
TEST(sys.memory.size > 0, "Creating conses affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
TEST(sys_cost(&sys) > 0, "Creating conses affects memory size");
|
||||
old_memory_size = sys_cost(&sys);
|
||||
|
||||
(void)cons(&sys, intern(&sys, SV_AUTO("test")), NIL);
|
||||
TEST(sys.memory.size > old_memory_size,
|
||||
TEST(sys_cost(&sys) > old_memory_size,
|
||||
"Creating conses back to back affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
old_memory_size = sys_cost(&sys);
|
||||
|
||||
// Creating vectors does affect memory size
|
||||
(void)make_vec(&sys, 8);
|
||||
TEST(sys.memory.size > old_memory_size,
|
||||
TEST(sys_cost(&sys) > old_memory_size,
|
||||
"Creating vectors (size 8) affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
old_memory_size = sys_cost(&sys);
|
||||
|
||||
(void)make_vec(&sys, 1000);
|
||||
TEST(sys.memory.size > old_memory_size,
|
||||
TEST(sys_cost(&sys) > old_memory_size,
|
||||
"Creating vectors (size 1000) affects memory size");
|
||||
old_memory_size = sys.memory.size;
|
||||
old_memory_size = sys_cost(&sys);
|
||||
|
||||
sys_free(&sys);
|
||||
TEST(sys.memory.size == 0, "sys_free cleans up memory (shallow check)");
|
||||
TEST(sys.symtable.count == 0, "sys_free cleans up symtable (shallow check)");
|
||||
|
||||
TEST_END();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user