Compare commits
12 Commits
500661d68e
...
10d6876de4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10d6876de4 | ||
|
|
75daad53ea | ||
|
|
1e451c57e8 | ||
|
|
d14f015c38 | ||
|
|
26e545a732 | ||
|
|
169a165cfc | ||
|
|
438a494ac7 | ||
|
|
068e4aa9f0 | ||
|
|
271e0bff9b | ||
|
|
010895331d | ||
|
|
6a75c1d9d4 | ||
|
|
01b695eb6a |
7
Makefile
7
Makefile
@@ -5,8 +5,8 @@ OUT=$(DIST)/alisp.out
|
||||
TEST=$(DIST)/test.out
|
||||
|
||||
LDFLAGS=
|
||||
GFLAGS=-Wall -Wextra -Wpedantic -std=c23 -I./include/
|
||||
DFLAGS=-ggdb -fsanitize=address -fsanitize=undefined
|
||||
GFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c23 -I./include/
|
||||
DFLAGS=-ggdb -fsanitize=address -fsanitize=undefined -DVERBOSE_LOGS=1
|
||||
RFLAGS=-O3
|
||||
|
||||
MODE=release
|
||||
@@ -61,6 +61,9 @@ run: $(OUT)
|
||||
test: $(TEST)
|
||||
./$^
|
||||
|
||||
examples: $(OUT)
|
||||
./$^ ./examples/hello-world.lisp
|
||||
|
||||
clean:
|
||||
rm -rf $(DIST)
|
||||
|
||||
|
||||
14
examples/hello-world.lisp
Normal file
14
examples/hello-world.lisp
Normal file
@@ -0,0 +1,14 @@
|
||||
;;; hello-world.lisp - 2026-02-04
|
||||
|
||||
;; 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/>.
|
||||
|
||||
(display "Hello, world!")
|
||||
@@ -19,6 +19,20 @@
|
||||
#define FAIL(MSG) assert(false && "FAIL: " #MSG)
|
||||
#define TODO(MSG) assert(false && "TODO: " #MSG)
|
||||
|
||||
#ifndef VERBOSE_LOGS
|
||||
#define VERBOSE_LOGS 0
|
||||
#endif
|
||||
|
||||
#if VERBOSE_LOGS
|
||||
#define LOG(...) \
|
||||
do \
|
||||
{ \
|
||||
printf(__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define LOG(...)
|
||||
#endif
|
||||
|
||||
/// Numeric aliases
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
|
||||
@@ -30,7 +30,7 @@ typedef struct
|
||||
|
||||
void sys_init(sys_t *);
|
||||
void sys_register(sys_t *, lisp_t *);
|
||||
void sys_cleanup(sys_t *);
|
||||
void sys_free(sys_t *);
|
||||
|
||||
/// Constructors and destructors
|
||||
lisp_t *make_int(i64);
|
||||
|
||||
@@ -8,13 +8,18 @@
|
||||
#ifndef READER_H
|
||||
#define READER_H
|
||||
|
||||
#include <alisp/lisp.h>
|
||||
#include <alisp/stream.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
READ_OK = 0,
|
||||
READ_ERR_OK = 0,
|
||||
READ_ERR_EOF,
|
||||
READ_ERR_UNKNOWN_CHAR,
|
||||
} read_err_t;
|
||||
|
||||
const char *read_err_to_cstr(read_err_t);
|
||||
|
||||
// Attempt to read an expression from the stream, storing it in a pointer,
|
||||
// returning any errors if failed.
|
||||
read_err_t read(sys_t *, stream_t *, lisp_t **);
|
||||
|
||||
@@ -22,13 +22,15 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STREAM_ERR_INVALID_PTR = -4,
|
||||
STREAM_ERR_FILE_NONEXISTENT = -3,
|
||||
STREAM_ERR_FILE_READ = -2,
|
||||
STREAM_ERR_PIPE_NONEXISTENT = -1,
|
||||
STREAM_ERR_OK = 0,
|
||||
STREAM_ERR_INVALID_PTR,
|
||||
STREAM_ERR_FILE_NONEXISTENT,
|
||||
STREAM_ERR_FILE_READ,
|
||||
STREAM_ERR_PIPE_NONEXISTENT,
|
||||
} stream_err_t;
|
||||
|
||||
const char *stream_err_to_cstr(stream_err_t);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec_t cache;
|
||||
@@ -80,6 +82,9 @@ sv_t stream_till(stream_t *, const char *);
|
||||
// present.
|
||||
sv_t stream_while(stream_t *, const char *);
|
||||
|
||||
// Get the line and column of the stream at its current position.
|
||||
void stream_line_col(stream_t *, u64 *line, u64 *col);
|
||||
|
||||
#endif
|
||||
|
||||
/* Copyright (C) 2026 Aryadev Chavali
|
||||
|
||||
@@ -22,7 +22,7 @@ void sys_register(sys_t *sys, lisp_t *ptr)
|
||||
vec_append(&sys->memory, &ptr, sizeof(&ptr));
|
||||
}
|
||||
|
||||
void sys_cleanup(sys_t *sys)
|
||||
void sys_free(sys_t *sys)
|
||||
{
|
||||
static_assert(NUM_TAGS == 5);
|
||||
|
||||
|
||||
43
src/reader.c
Normal file
43
src/reader.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/* reader.c: Stream reader implementation
|
||||
* Created: 2026-02-04
|
||||
* Author: Aryadev Chavali
|
||||
* License: See end of file
|
||||
* Commentary:
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <alisp/base.h>
|
||||
#include <alisp/reader.h>
|
||||
|
||||
const char *read_err_to_cstr(read_err_t err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case READ_ERR_OK:
|
||||
return "OK";
|
||||
break;
|
||||
case READ_ERR_EOF:
|
||||
return "EOF";
|
||||
break;
|
||||
case READ_ERR_UNKNOWN_CHAR:
|
||||
return "UNKNOWN_CHAR";
|
||||
break;
|
||||
default:
|
||||
FAIL("Unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
/* 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/>.
|
||||
|
||||
*/
|
||||
70
src/stream.c
70
src/stream.c
@@ -8,8 +8,33 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <alisp/base.h>
|
||||
#include <alisp/stream.h>
|
||||
|
||||
const char *stream_err_to_cstr(stream_err_t err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case STREAM_ERR_INVALID_PTR:
|
||||
return "INVALID PTR";
|
||||
break;
|
||||
case STREAM_ERR_FILE_NONEXISTENT:
|
||||
return "FILE NONEXISTENT";
|
||||
break;
|
||||
case STREAM_ERR_FILE_READ:
|
||||
return "FILE READ";
|
||||
break;
|
||||
case STREAM_ERR_PIPE_NONEXISTENT:
|
||||
return "PIPE NONEXISTENT";
|
||||
break;
|
||||
case STREAM_ERR_OK:
|
||||
return "OK";
|
||||
break;
|
||||
default:
|
||||
FAIL("Unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
stream_err_t stream_init_string(stream_t *stream, char *name, sv_t contents)
|
||||
{
|
||||
if (!stream)
|
||||
@@ -26,8 +51,11 @@ stream_err_t stream_init_string(stream_t *stream, char *name, sv_t contents)
|
||||
|
||||
stream_err_t stream_init_pipe(stream_t *stream, char *name, FILE *pipe)
|
||||
{
|
||||
if (!stream || !pipe)
|
||||
if (!stream)
|
||||
return STREAM_ERR_INVALID_PTR;
|
||||
else if (!pipe)
|
||||
return STREAM_ERR_PIPE_NONEXISTENT;
|
||||
|
||||
name = name ? name : "<stream>";
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
|
||||
@@ -42,8 +70,11 @@ stream_err_t stream_init_pipe(stream_t *stream, char *name, FILE *pipe)
|
||||
|
||||
stream_err_t stream_init_file(stream_t *stream, char *name, FILE *pipe)
|
||||
{
|
||||
if (!stream || !pipe)
|
||||
if (!stream)
|
||||
return STREAM_ERR_INVALID_PTR;
|
||||
else if (!pipe)
|
||||
return STREAM_ERR_FILE_NONEXISTENT;
|
||||
|
||||
name = name ? name : "<stream>";
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
|
||||
@@ -361,6 +392,41 @@ sv_t stream_while(stream_t *stream, const char *str)
|
||||
return stream_substr_abs(stream, current_position, size - 1);
|
||||
}
|
||||
|
||||
void stream_line_col(stream_t *stream, u64 *line, u64 *col)
|
||||
{
|
||||
if (!stream || !line || !col)
|
||||
return;
|
||||
// Go through the cache, byte by byte.
|
||||
char *cache = NULL;
|
||||
u64 size = 0;
|
||||
if (stream->type == STREAM_TYPE_STRING)
|
||||
{
|
||||
cache = stream->string.data;
|
||||
size = stream->string.size;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = (char *)vec_data(&stream->pipe.cache);
|
||||
size = stream->pipe.cache.size;
|
||||
}
|
||||
|
||||
*line = 1;
|
||||
*col = 0;
|
||||
for (u64 i = 0; i < size; ++i)
|
||||
{
|
||||
char c = cache[i];
|
||||
if (c == '\n')
|
||||
{
|
||||
*line += 1;
|
||||
*col = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*col += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copyright (C) 2025, 2026 Aryadev Chavali
|
||||
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
|
||||
@@ -60,7 +60,7 @@ void sym_test(void)
|
||||
TEST(strncmp(in, out, strlen(in)) == 0, "%d", strncmp(in, out, strlen(in)));
|
||||
}
|
||||
TEST_PASSED();
|
||||
sys_cleanup(&system);
|
||||
sys_free(&system);
|
||||
}
|
||||
|
||||
void cons_test(void)
|
||||
@@ -91,7 +91,7 @@ void cons_test(void)
|
||||
|
||||
TEST_PASSED();
|
||||
|
||||
sys_cleanup(&system);
|
||||
sys_free(&system);
|
||||
}
|
||||
|
||||
const test_fn TESTS_LISP_API[] = {
|
||||
|
||||
@@ -32,7 +32,7 @@ void vec_test1(void)
|
||||
strncmp((char *)vec_data(vec), words_text, vec->size));
|
||||
|
||||
TEST_PASSED();
|
||||
sys_cleanup(&system);
|
||||
sys_free(&system);
|
||||
}
|
||||
|
||||
void vec_test2(void)
|
||||
@@ -65,7 +65,7 @@ void vec_test2(void)
|
||||
}
|
||||
|
||||
TEST_PASSED();
|
||||
sys_cleanup(&system);
|
||||
sys_free(&system);
|
||||
}
|
||||
|
||||
const test_fn TESTS_VEC[] = {
|
||||
|
||||
Reference in New Issue
Block a user