diff options
| author | bozo.kopic <bozo@kopic.xyz> | 2022-08-02 01:20:12 +0200 |
|---|---|---|
| committer | bozo.kopic <bozo@kopic.xyz> | 2022-09-25 02:40:23 +0200 |
| commit | 288727f09a1b3458c268497d111349e608c3f9fa (patch) | |
| tree | d62565249fa3c7127856c65405752572fc41aca9 /src_c | |
Diffstat (limited to 'src_c')
| -rw-r--r-- | src_c/apply.c | 140 | ||||
| -rw-r--r-- | src_c/apply.h | 10 | ||||
| -rw-r--r-- | src_c/arch.h | 63 | ||||
| -rw-r--r-- | src_c/arch/avr8.c | 63 | ||||
| -rw-r--r-- | src_c/arch/avr8.h | 30 | ||||
| -rw-r--r-- | src_c/arch/posix.c | 54 | ||||
| -rw-r--r-- | src_c/arch/posix.h | 30 | ||||
| -rw-r--r-- | src_c/buff.c | 61 | ||||
| -rw-r--r-- | src_c/buff.h | 23 | ||||
| -rw-r--r-- | src_c/builtin.c | 65 | ||||
| -rw-r--r-- | src_c/builtin.h | 24 | ||||
| -rw-r--r-- | src_c/cell.c | 50 | ||||
| -rw-r--r-- | src_c/cell.h | 215 | ||||
| -rw-r--r-- | src_c/ctx.c | 231 | ||||
| -rw-r--r-- | src_c/ctx.h | 16 | ||||
| -rw-r--r-- | src_c/env.c | 86 | ||||
| -rw-r--r-- | src_c/env.h | 30 | ||||
| -rw-r--r-- | src_c/eval.c | 92 | ||||
| -rw-r--r-- | src_c/eval.h | 9 | ||||
| -rw-r--r-- | src_c/function.c | 582 | ||||
| -rw-r--r-- | src_c/function.h | 54 | ||||
| -rw-r--r-- | src_c/main.c | 55 | ||||
| -rw-r--r-- | src_c/mem.c | 478 | ||||
| -rw-r--r-- | src_c/mem.h | 189 | ||||
| -rw-r--r-- | src_c/read.c | 428 | ||||
| -rw-r--r-- | src_c/read.h | 10 | ||||
| -rw-r--r-- | src_c/repl.c | 104 | ||||
| -rw-r--r-- | src_c/repl.h | 9 | ||||
| -rw-r--r-- | src_c/status.h | 25 | ||||
| -rw-r--r-- | src_c/stream.c | 108 | ||||
| -rw-r--r-- | src_c/stream.h | 46 | ||||
| -rw-r--r-- | src_c/syntax.c | 192 | ||||
| -rw-r--r-- | src_c/syntax.h | 17 | ||||
| -rw-r--r-- | src_c/write.c | 174 | ||||
| -rw-r--r-- | src_c/write.h | 10 |
35 files changed, 3773 insertions, 0 deletions
diff --git a/src_c/apply.c b/src_c/apply.c new file mode 100644 index 0000000..4dd8684 --- /dev/null +++ b/src_c/apply.c @@ -0,0 +1,140 @@ +#include "apply.h" +#include "ctx.h" +#include "eval.h" +#include "function.h" +#include "syntax.h" +#include "write.h" + + +static lsp_status_t create_ctx(lsp_env_t *e, lsp_addr_t parent_ctx, + lsp_addr_t arg_names, lsp_addr_t arg_values, + lsp_addr_t *result) { + lsp_status_t status = lsp_ctx_copy(e->m, parent_ctx, result); + if (status != LSP_SUCCESS) + return status; + + while (arg_names != e->m->nil) { + if (lsp_mem_is_symbol(e->m, arg_names)) { + status = lsp_ctx_add(e->m, *result, arg_names, arg_values); + arg_values = e->m->nil; + break; + } + + if (arg_values == e->m->nil) { + status = LSP_ERR_ARG_COUNT; + break; + } + + lsp_addr_t arg_name = lsp_mem_get_pair_first(e->m, arg_names); + lsp_addr_t arg_value = lsp_mem_get_pair_first(e->m, arg_values); + + if (!lsp_mem_is_symbol(e->m, arg_name)) { + status = LSP_ERR_ARG_TYPE; + break; + } + + status = lsp_ctx_add(e->m, *result, arg_name, arg_value); + if (status != LSP_SUCCESS) + break; + + arg_names = lsp_mem_get_pair_second(e->m, arg_names); + arg_values = lsp_mem_get_pair_second(e->m, arg_values); + } + + if (status == LSP_SUCCESS && arg_values != e->m->nil) + status = LSP_ERR_ARG_COUNT; + + if (status != LSP_SUCCESS) + lsp_mem_dec_ref(e->m, *result); + + return status; +} + + +static lsp_status_t apply_builtin_function(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t callable, + lsp_addr_t args) { + lsp_uint16_t index = lsp_mem_get_builtin_index(e->m, callable); + lsp_builtin_cb_t cb = lsp_functions[index].cb; + return cb(e, ctx, args); +} + + +static lsp_status_t apply_builtin_syntax(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t callable, lsp_addr_t args) { + lsp_uint16_t index = lsp_mem_get_builtin_index(e->m, callable); + lsp_builtin_cb_t cb = lsp_syntaxes[index].cb; + return cb(e, ctx, args); +} + + +static lsp_status_t apply_function(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t callable, lsp_addr_t args) { + lsp_addr_t parent_ctx = lsp_mem_get_function_parent_ctx(e->m, callable); + lsp_addr_t arg_names = lsp_mem_get_function_args(e->m, callable); + lsp_addr_t body = lsp_mem_get_function_body(e->m, callable); + + lsp_addr_t fn_ctx; + lsp_status_t status = create_ctx(e, parent_ctx, arg_names, args, &fn_ctx); + if (status != LSP_SUCCESS) + return status; + + status = lsp_syntax_begin(e, fn_ctx, body); + lsp_mem_dec_ref(e->m, fn_ctx); + return status; +} + + +static lsp_status_t apply_syntax(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t callable, lsp_addr_t args) { + lsp_addr_t parent_ctx = lsp_mem_get_syntax_parent_ctx(e->m, callable); + lsp_addr_t arg_names = lsp_mem_get_syntax_args(e->m, callable); + lsp_addr_t body = lsp_mem_get_syntax_body(e->m, callable); + + lsp_addr_t syntax_ctx; + lsp_status_t status = + create_ctx(e, parent_ctx, arg_names, args, &syntax_ctx); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t result = e->m->nil; + while (body != e->m->nil) { + lsp_mem_dec_ref(e->m, result); + + lsp_addr_t value = lsp_mem_get_pair_first(e->m, body); + status = lsp_env_resolve(e, syntax_ctx, value, &result); + if (status != LSP_SUCCESS) + break; + + body = lsp_mem_get_pair_second(e->m, body); + } + + lsp_mem_dec_ref(e->m, syntax_ctx); + if (status != LSP_SUCCESS) + return status; + + // lsp_write(e->m, e->out, result); + // lsp_out_stream_write(e->out, '\n'); + + status = lsp_env_set_result_eval(e, ctx, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_apply(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t callable, + lsp_addr_t args) { + if (lsp_mem_is_builtin_function(e->m, callable)) + return apply_builtin_function(e, ctx, callable, args); + + if (lsp_mem_is_builtin_syntax(e->m, callable)) + return apply_builtin_syntax(e, ctx, callable, args); + + if (lsp_mem_is_function(e->m, callable)) + return apply_function(e, ctx, callable, args); + + if (lsp_mem_is_syntax(e->m, callable)) + return apply_syntax(e, ctx, callable, args); + + return LSP_ERR_APPLY; +} diff --git a/src_c/apply.h b/src_c/apply.h new file mode 100644 index 0000000..ef4e1c2 --- /dev/null +++ b/src_c/apply.h @@ -0,0 +1,10 @@ +#ifndef LISP16_APPLY_H +#define LISP16_APPLY_H + +#include "env.h" + + +lsp_status_t lsp_apply(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t callable, + lsp_addr_t args); + +#endif diff --git a/src_c/arch.h b/src_c/arch.h new file mode 100644 index 0000000..01ae8d9 --- /dev/null +++ b/src_c/arch.h @@ -0,0 +1,63 @@ +#ifndef LISP16_ARCH_H +#define LISP16_ARCH_H + +#define LSP_ARCH_POSIX 0 +#define LSP_ARCH_AVR8 1 +#define LSP_ARCH_STM32 2 + +#ifndef LSP_ARCH +#error LSP_ARCH not defined +#endif + +#if LSP_ARCH == LSP_ARCH_POSIX + +#include <stdint.h> +typedef _Bool lsp_bool_t; +typedef int8_t lsp_int8_t; +typedef int16_t lsp_int16_t; +typedef int32_t lsp_int32_t; +typedef uint8_t lsp_uint8_t; +typedef uint16_t lsp_uint16_t; +typedef uint32_t lsp_uint32_t; + +#elif LSP_ARCH == LSP_ARCH_AVR8 + +#include <stdint.h> +typedef _Bool lsp_bool_t; +typedef int8_t lsp_int8_t; +typedef int16_t lsp_int16_t; +typedef int32_t lsp_int32_t; +typedef uint8_t lsp_uint8_t; +typedef uint16_t lsp_uint16_t; +typedef uint32_t lsp_uint32_t; + +#elif LSP_ARCH == LSP_ARCH_STM32 + +#include <stdint.h> +typedef _Bool lsp_bool_t; +typedef int8_t lsp_int8_t; +typedef int16_t lsp_int16_t; +typedef int32_t lsp_int32_t; +typedef uint8_t lsp_uint8_t; +typedef uint16_t lsp_uint16_t; +typedef uint32_t lsp_uint32_t; + +#else + +#error unknown LSP_ARCH + +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef true +#define true ((lsp_bool_t)1) +#endif + +#ifndef false +#define false ((lsp_bool_t)0) +#endif + +#endif diff --git a/src_c/arch/avr8.c b/src_c/arch/avr8.c new file mode 100644 index 0000000..cbc454b --- /dev/null +++ b/src_c/arch/avr8.c @@ -0,0 +1,63 @@ +#include "avr8.h" +#include <avr/io.h> + +#define MEM_SIZE 0x01c0 +#define UART_BAUD 9600 + + +static lsp_int16_t avr8_getchar(lsp_in_stream_t *s) { + while (!(UCSR0A & (1 << 7))) + ; + return UDR0; +} + + +static lsp_int16_t avr8_putchar(lsp_out_stream_t *s, lsp_int16_t c) { + while (!(UCSR0A & (1 << 5))) + ; + UDR0 = c; +} + + +static lsp_uint8_t avr8_mem[sizeof(lsp_mem_t) + MEM_SIZE * sizeof(lsp_cell_t)]; + +static lsp_in_stream_t avr8_in_stream; + +static lsp_out_stream_t avr8_out_stream; + + +void lsp_arch_avr8_init() { + UBRR0 = F_CPU / 16 / UART_BAUD - 1; + UCSR0B |= _BV(TXEN0) | _BV(RXEN0); +} + + +lsp_mem_t *lsp_arch_avr8_create_mem() { + lsp_mem_t *m = (void *)avr8_mem; + if (lsp_mem_init(m, MEM_SIZE) != LSP_SUCCESS) + return NULL; + return m; +} + + +void lsp_arch_avr8_free_mem(lsp_mem_t *m) {} + + +lsp_in_stream_t *lsp_arch_avr8_create_in_stream() { + lsp_in_stream_t *s = &avr8_in_stream; + lsp_in_stream_init(s, avr8_getchar); + return s; +} + + +void lsp_arch_avr8_free_in_stream(lsp_in_stream_t *s) {} + + +lsp_out_stream_t *lsp_arch_avr8_create_out_stream() { + lsp_out_stream_t *s = &avr8_out_stream; + lsp_out_stream_init(s, avr8_putchar); + return s; +} + + +void lsp_arch_avr8_free_out_stream(lsp_out_stream_t *s) {} diff --git a/src_c/arch/avr8.h b/src_c/arch/avr8.h new file mode 100644 index 0000000..351ee14 --- /dev/null +++ b/src_c/arch/avr8.h @@ -0,0 +1,30 @@ +#ifndef LISP16_ARCH_AVR8_H +#define LISP16_ARCH_AVR8_H + +#include "../mem.h" +#include "../stream.h" + +#define LSP_ARCH_INIT lsp_arch_avr8_init + +#define LSP_ARCH_CREATE_MEM lsp_arch_avr8_create_mem +#define LSP_ARCH_FREE_MEM lsp_arch_avr8_free_mem + +#define LSP_ARCH_CREATE_IN_STREAM lsp_arch_avr8_create_in_stream +#define LSP_ARCH_FREE_IN_STREAM lsp_arch_avr8_free_in_stream + +#define LSP_ARCH_CREATE_OUT_STREAM lsp_arch_avr8_create_out_stream +#define LSP_ARCH_FREE_OUT_STREAM lsp_arch_avr8_free_out_stream + + +void lsp_arch_avr8_init(); + +lsp_mem_t *lsp_arch_avr8_create_mem(); +void lsp_arch_avr8_free_mem(lsp_mem_t *m); + +lsp_in_stream_t *lsp_arch_avr8_create_in_stream(); +void lsp_arch_avr8_free_in_stream(lsp_in_stream_t *s); + +lsp_out_stream_t *lsp_arch_avr8_create_out_stream(); +void lsp_arch_avr8_free_out_stream(lsp_out_stream_t *s); + +#endif diff --git a/src_c/arch/posix.c b/src_c/arch/posix.c new file mode 100644 index 0000000..19e33a1 --- /dev/null +++ b/src_c/arch/posix.c @@ -0,0 +1,54 @@ +#include "posix.h" +#include <stdio.h> +#include <stdlib.h> + +#define MEM_SIZE 0x4000 + + +static lsp_int16_t posix_getchar(lsp_in_stream_t *s) { + int c = getchar(); + if (c == EOF) + return LSP_EOF; + return c; +} + + +static lsp_int16_t posix_putchar(lsp_out_stream_t *s, lsp_int16_t c) { + return putchar(c); +} + + +void lsp_arch_posix_init() {} + + +lsp_mem_t *lsp_arch_posix_create_mem() { + lsp_mem_t *m = malloc(sizeof(lsp_mem_t) + sizeof(lsp_cell_t) * MEM_SIZE); + if (lsp_mem_init(m, MEM_SIZE) != LSP_SUCCESS) { + free(m); + return NULL; + } + return m; +} + + +void lsp_arch_posix_free_mem(lsp_mem_t *m) { free(m); } + + +lsp_in_stream_t *lsp_arch_posix_create_in_stream() { + lsp_in_stream_t *s = malloc(sizeof(lsp_in_stream_t)); + lsp_in_stream_init(s, posix_getchar); + return s; +} + + +void lsp_arch_posix_free_in_stream(lsp_in_stream_t *s) { free(s); } + + +lsp_out_stream_t *lsp_arch_posix_create_out_stream() { + lsp_out_stream_t *s = malloc(sizeof(lsp_out_stream_t)); + lsp_out_stream_init(s, posix_putchar); + return s; +} + + +void lsp_arch_posix_free_out_stream(lsp_out_stream_t *s) { free(s); } diff --git a/src_c/arch/posix.h b/src_c/arch/posix.h new file mode 100644 index 0000000..5716c0a --- /dev/null +++ b/src_c/arch/posix.h @@ -0,0 +1,30 @@ +#ifndef LISP16_ARCH_POSIX_H +#define LISP16_ARCH_POSIX_H + +#include "../mem.h" +#include "../stream.h" + +#define LSP_ARCH_INIT lsp_arch_posix_init + +#define LSP_ARCH_CREATE_MEM lsp_arch_posix_create_mem +#define LSP_ARCH_FREE_MEM lsp_arch_posix_free_mem + +#define LSP_ARCH_CREATE_IN_STREAM lsp_arch_posix_create_in_stream +#define LSP_ARCH_FREE_IN_STREAM lsp_arch_posix_free_in_stream + +#define LSP_ARCH_CREATE_OUT_STREAM lsp_arch_posix_create_out_stream +#define LSP_ARCH_FREE_OUT_STREAM lsp_arch_posix_free_out_stream + + +void lsp_arch_posix_init(); + +lsp_mem_t *lsp_arch_posix_create_mem(); +void lsp_arch_posix_free_mem(lsp_mem_t *m); + +lsp_in_stream_t *lsp_arch_posix_create_in_stream(); +void lsp_arch_posix_free_in_stream(lsp_in_stream_t *s); + +lsp_out_stream_t *lsp_arch_posix_create_out_stream(); +void lsp_arch_posix_free_out_stream(lsp_out_stream_t *s); + +#endif diff --git a/src_c/buff.c b/src_c/buff.c new file mode 100644 index 0000000..e22eba8 --- /dev/null +++ b/src_c/buff.c @@ -0,0 +1,61 @@ +#include "buff.h" + + +static lsp_status_t update_str(lsp_buff_t *b) { + lsp_uint16_t value_len = + ((b->value == b->m->nil) ? 0 : lsp_mem_get_string_len(b->m, b->value)); + + lsp_addr_t value; + lsp_status_t status = + lsp_mem_create_string(b->m, value_len + b->buff_len, &value); + if (status != LSP_SUCCESS) + return status; + + for (lsp_uint16_t i = 0; i < value_len; ++i) + lsp_mem_set_string_data(b->m, value, i, + lsp_mem_get_string_data(b->m, b->value, i)); + + for (lsp_uint16_t i = 0; i < b->buff_len; ++i) + lsp_mem_set_string_data(b->m, value, i + value_len, b->buff[i]); + + lsp_mem_dec_ref(b->m, b->value); + b->value = value; + b->buff_len = 0; + return LSP_SUCCESS; +} + + +void lsp_buff_init(lsp_buff_t *b, lsp_mem_t *m) { + b->m = m; + b->value = m->nil; + b->buff_len = 0; +} + + +lsp_status_t lsp_buff_push(lsp_buff_t *b, lsp_uint8_t c) { + if (b->buff_len + 1 >= LSP_BUFF_SIZE) { + lsp_status_t status = update_str(b); + if (status != LSP_SUCCESS) + return status; + } + + b->buff[b->buff_len++] = c; + return LSP_SUCCESS; +} + + +lsp_status_t lsp_buff_pop(lsp_buff_t *b, lsp_addr_t *value) { + lsp_status_t status = update_str(b); + if (status != LSP_SUCCESS) + return status; + + *value = b->value; + b->value = b->m->nil; + return LSP_SUCCESS; +} + + +void lsp_buff_clear(lsp_buff_t *b) { + lsp_mem_dec_ref(b->m, b->value); + b->value = b->m->nil; +} diff --git a/src_c/buff.h b/src_c/buff.h new file mode 100644 index 0000000..d17694c --- /dev/null +++ b/src_c/buff.h @@ -0,0 +1,23 @@ +#ifndef LISP16_BUFF_H +#define LISP16_BUFF_H + +#include "mem.h" +#include "status.h" + +#define LSP_BUFF_SIZE 32 + + +typedef struct { + lsp_mem_t *m; + lsp_addr_t value; + lsp_uint8_t buff[LSP_BUFF_SIZE]; + lsp_uint8_t buff_len; +} lsp_buff_t; + + +void lsp_buff_init(lsp_buff_t *b, lsp_mem_t *m); +lsp_status_t lsp_buff_push(lsp_buff_t *b, lsp_uint8_t c); +lsp_status_t lsp_buff_pop(lsp_buff_t *b, lsp_addr_t *value); +void lsp_buff_clear(lsp_buff_t *b); + +#endif diff --git a/src_c/builtin.c b/src_c/builtin.c new file mode 100644 index 0000000..92e1fa8 --- /dev/null +++ b/src_c/builtin.c @@ -0,0 +1,65 @@ +#include "builtin.h" + + +lsp_status_t lsp_builtin_get_args_1(lsp_mem_t *m, lsp_addr_t args, + lsp_addr_t *arg1) { + if (args == m->nil) + return LSP_ERR_ARG_COUNT; + + *arg1 = lsp_mem_get_pair_first(m, args); + + args = lsp_mem_get_pair_second(m, args); + if (args != m->nil) + return LSP_ERR_ARG_COUNT; + + return LSP_SUCCESS; +} + + +lsp_status_t lsp_builtin_get_args_2(lsp_mem_t *m, lsp_addr_t args, + lsp_addr_t *arg1, lsp_addr_t *arg2) { + if (args == m->nil) + return LSP_ERR_ARG_COUNT; + + *arg1 = lsp_mem_get_pair_first(m, args); + + args = lsp_mem_get_pair_second(m, args); + if (args == m->nil) + return LSP_ERR_ARG_COUNT; + + *arg2 = lsp_mem_get_pair_first(m, args); + + args = lsp_mem_get_pair_second(m, args); + if (args != m->nil) + return LSP_ERR_ARG_COUNT; + + return LSP_SUCCESS; +} + + +lsp_status_t lsp_builtin_get_args_3(lsp_mem_t *m, lsp_addr_t args, + lsp_addr_t *arg1, lsp_addr_t *arg2, + lsp_addr_t *arg3) { + if (args == m->nil) + return LSP_ERR_ARG_COUNT; + + *arg1 = lsp_mem_get_pair_first(m, args); + + args = lsp_mem_get_pair_second(m, args); + if (args == m->nil) + return LSP_ERR_ARG_COUNT; + + *arg2 = lsp_mem_get_pair_first(m, args); + + args = lsp_mem_get_pair_second(m, args); + if (args == m->nil) + return LSP_ERR_ARG_COUNT; + + *arg3 = lsp_mem_get_pair_first(m, args); + + args = lsp_mem_get_pair_second(m, args); + if (args != m->nil) + return LSP_ERR_ARG_COUNT; + + return LSP_SUCCESS; +} diff --git a/src_c/builtin.h b/src_c/builtin.h new file mode 100644 index 0000000..af9fb51 --- /dev/null +++ b/src_c/builtin.h @@ -0,0 +1,24 @@ +#ifndef LISP16_BUILTIN_H +#define LISP16_BUILTIN_H + +#include "env.h" + + +typedef lsp_status_t (*lsp_builtin_cb_t)(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); + +typedef struct { + char *name; + lsp_builtin_cb_t cb; +} lsp_builtin_entry_t; + + +lsp_status_t lsp_builtin_get_args_1(lsp_mem_t *m, lsp_addr_t args, + lsp_addr_t *arg1); +lsp_status_t lsp_builtin_get_args_2(lsp_mem_t *m, lsp_addr_t args, + lsp_addr_t *arg1, lsp_addr_t *arg2); +lsp_status_t lsp_builtin_get_args_3(lsp_mem_t *m, lsp_addr_t args, + lsp_addr_t *arg1, lsp_addr_t *arg2, + lsp_addr_t *arg3); + +#endif diff --git a/src_c/cell.c b/src_c/cell.c new file mode 100644 index 0000000..66da137 --- /dev/null +++ b/src_c/cell.c @@ -0,0 +1,50 @@ +#include "cell.h" + + +lsp_uint16_t lsp_cell_get_size(lsp_cell_t *c) { + if (lsp_cell_is_number(c)) { + if (!(c[0] & 0x2000)) + return 1; + + for (lsp_uint8_t i = 1; true; ++i) { + if (!(c[i] & 0x4000)) + return i + 1; + } + + } else if (lsp_cell_is_pair(c)) { + return 2; + + } else if (lsp_cell_is_string_or_symbol(c)) { + return lsp_cell_get_string_symbol_size(*c & 0x07ff); + + } else if (lsp_cell_is_builtin(c)) { + return 1; + + } else if (lsp_cell_is_function_or_syntax(c)) { + return 4; + } + + return 0; +} + + +lsp_uint16_t lsp_cell_get_number_size(lsp_int32_t value) { + lsp_bool_t msb = ((value & 0x1000) ? true : false); + value >>= 13; + if (value == 0 || value == -1) + return 1 + ((msb && !value) ? 1 : 0); + + for (lsp_uint8_t i = 0; 1; ++i) { + msb = ((value & 0x4000) ? 1 : 0); + value >>= 15; + if (value == 0 || value == -1) + return i + 2 + ((msb && !value) ? 1 : 0); + } + + return 0; +} + + +lsp_uint16_t lsp_cell_get_string_symbol_size(lsp_uint16_t len) { + return (((lsp_uint32_t)len << 3) / 15) + ((len % 15) ? 1 : 0) + 1; +} diff --git a/src_c/cell.h b/src_c/cell.h new file mode 100644 index 0000000..b8ed7c0 --- /dev/null +++ b/src_c/cell.h @@ -0,0 +1,215 @@ +#ifndef LISP16_CELL_H +#define LISP16_CELL_H + +#include "arch.h" + + +typedef lsp_uint16_t lsp_cell_t; +typedef lsp_uint16_t lsp_addr_t; // 14 least significant bits used + + +lsp_uint16_t lsp_cell_get_size(lsp_cell_t *c); +lsp_uint16_t lsp_cell_get_number_size(lsp_int32_t value); +lsp_uint16_t lsp_cell_get_string_symbol_size(lsp_uint16_t len); + + +static inline lsp_bool_t lsp_cell_is_number(lsp_cell_t *c) { + return (*c & 0x4000) == 0x0000; +} + +static inline lsp_bool_t lsp_cell_is_pair(lsp_cell_t *c) { + return (*c & 0x6000) == 0x4000; +} + +static inline lsp_bool_t lsp_cell_is_string(lsp_cell_t *c) { + return (*c & 0x7800) == 0x6000; +} + +static inline lsp_bool_t lsp_cell_is_symbol(lsp_cell_t *c) { + return (*c & 0x7800) == 0x6800; +} + +static inline lsp_bool_t lsp_cell_is_builtin_function(lsp_cell_t *c) { + return (*c & 0x7c00) == 0x7000; +} + +static inline lsp_bool_t lsp_cell_is_builtin_syntax(lsp_cell_t *c) { + return (*c & 0x7c00) == 0x7400; +} + +static inline lsp_bool_t lsp_cell_is_function(lsp_cell_t *c) { + return (*c & 0x7c00) == 0x7800; +} + +static inline lsp_bool_t lsp_cell_is_syntax(lsp_cell_t *c) { + return (*c & 0x7c00) == 0x7c00; +} + +static inline lsp_bool_t lsp_cell_is_string_or_symbol(lsp_cell_t *c) { + return (*c & 0x7000) == 0x6000; +} + +static inline lsp_bool_t lsp_cell_is_builtin(lsp_cell_t *c) { + return (*c & 0x7800) == 0x7000; +} + +static inline lsp_bool_t lsp_cell_is_function_or_syntax(lsp_cell_t *c) { + return (*c & 0x7800) == 0x7800; +} + + +static inline void lsp_cell_set_number(lsp_cell_t *c, lsp_int32_t value) { + lsp_uint8_t size = lsp_cell_get_number_size(value); + for (lsp_uint8_t i = 0; i < size; ++i) { + lsp_uint8_t shift = (size - i - 1) * 14; + c[i] = (value >> shift) & (i ? 0x3fff : 0x1fff); + if (i != size - 1) + c[i] |= (i ? 0x4000 : 0x2000); + } +} + +static inline void lsp_cell_set_pair(lsp_cell_t *c, lsp_addr_t first, + lsp_addr_t second) { + c[0] = 0x4000 | ((first >> 1) & 0x1fff); + c[1] = ((first & 1) ? 0x4000 : 0) | (second & 0x3fff); +} + +static inline void lsp_cell_set_string(lsp_cell_t *c, lsp_uint16_t data_len) { + lsp_uint16_t size = lsp_cell_get_string_symbol_size(data_len); + c[0] = 0x6000 | (data_len & 0x07ff); + for (lsp_uint16_t i = 1; i < size; ++i) + c[i] = 0; +} + +static inline void lsp_cell_set_string_data(lsp_cell_t *c, lsp_uint16_t i, + lsp_uint8_t data_i) { + lsp_uint32_t bit_count = (lsp_uint32_t)i << 3; + lsp_uint16_t start_cell = bit_count / 15; + lsp_uint8_t bit_shift = bit_count % 15; + lsp_uint16_t mask = 0x7f80 >> bit_shift; + if (bit_shift < 8) { + c[1 + start_cell] = (c[1 + start_cell] & ~mask) | + ((lsp_uint16_t)data_i << (7 - bit_shift)); + } else { + c[1 + start_cell] = + (c[1 + start_cell] & ~mask) | (data_i >> (bit_shift - 7)); + bit_shift = 22 - bit_shift; + mask = (0xffff << bit_shift) & 0x7fff; + c[2 + start_cell] = (c[2 + start_cell] & ~mask) | + (((lsp_uint16_t)data_i << bit_shift) & mask); + } +} + +static inline void lsp_cell_set_symbol(lsp_cell_t *c, lsp_uint16_t name_len) { + lsp_uint16_t size = lsp_cell_get_string_symbol_size(name_len); + c[0] = 0x6800 | (name_len & 0x07ff); + for (lsp_uint16_t i = 1; i < size; ++i) + c[i] = 0; +} + +static inline void lsp_cell_set_symbol_name(lsp_cell_t *c, lsp_uint16_t i, + lsp_uint8_t name_i) { + lsp_cell_set_string_data(c, i, name_i); +} + +static inline void lsp_cell_set_builtin_function(lsp_cell_t *c, + lsp_uint16_t index) { + *c = 0x7000 | (index & 0x03ff); +} + +static inline void lsp_cell_set_builtin_syntax(lsp_cell_t *c, + lsp_uint16_t index) { + *c = 0x7400 | (index & 0x03ff); +} + +static inline void lsp_cell_set_function(lsp_cell_t *c, lsp_addr_t parent_ctx, + lsp_addr_t args, lsp_addr_t body) { + c[0] = 0x7800; + c[1] = parent_ctx & 0x3fff; + c[2] = args & 0x3fff; + c[3] = body & 0x3fff; +} + +static inline void lsp_cell_set_syntax(lsp_cell_t *c, lsp_addr_t parent_ctx, + lsp_addr_t args, lsp_addr_t body) { + c[0] = 0x7c00; + c[1] = parent_ctx & 0x3fff; + c[2] = args & 0x3fff; + c[3] = body & 0x3fff; +} + + +static inline lsp_int32_t lsp_cell_get_number(lsp_cell_t *c) { + lsp_int32_t v = ((c[0] & 0x1000) ? -1 : 0); + v = (v << 12) | (c[0] & 0x0fff); + if (!(c[0] & 0x2000)) + return v; + for (lsp_uint8_t i = 1; 1; ++i) { + v = (v << 14) | (c[1] & 0x3fff); + if (!(c[i] & 0x4000)) + return v; + } +} + +static inline lsp_addr_t lsp_cell_get_pair_first(lsp_cell_t *c) { + return ((c[0] & 0x1fff) << 1) + ((c[1] & 0x4000) ? 1 : 0); +} + +static inline lsp_addr_t lsp_cell_get_pair_second(lsp_cell_t *c) { + return c[1] & 0x3fff; +} + +static inline lsp_uint16_t lsp_cell_get_string_len(lsp_cell_t *c) { + return *c & 0x07ff; +} + +static inline lsp_uint8_t lsp_cell_get_string_data(lsp_cell_t *c, + lsp_uint16_t i) { + lsp_uint32_t bit_count = (lsp_uint32_t)i << 3; + lsp_uint16_t start_cell = bit_count / 15; + lsp_uint8_t start_bit = 14 - (bit_count % 15); + if (start_bit >= 7) + return (c[1 + start_cell] >> (start_bit - 7)) & 0xff; + return ((c[1 + start_cell] << (7 - start_bit)) | + ((c[2 + start_cell] & 0x7fff) >> (8 + start_bit))) & + 0xff; +} + +static inline lsp_uint16_t lsp_cell_get_symbol_len(lsp_cell_t *c) { + return lsp_cell_get_string_len(c); +} + +static inline lsp_uint8_t lsp_cell_get_symbol_name(lsp_cell_t *c, + lsp_uint16_t i) { + return lsp_cell_get_string_data(c, i); +} + +static inline lsp_uint16_t lsp_cell_get_builtin_index(lsp_cell_t *c) { + return *c & 0x03ff; +} + +static inline lsp_addr_t lsp_cell_get_function_parent_ctx(lsp_cell_t *c) { + return c[1] & 0x3fff; +} + +static inline lsp_addr_t lsp_cell_get_function_args(lsp_cell_t *c) { + return c[2] & 0x3fff; +} + +static inline lsp_addr_t lsp_cell_get_function_body(lsp_cell_t *c) { + return c[3] & 0x3fff; +} + +static inline lsp_addr_t lsp_cell_get_syntax_parent_ctx(lsp_cell_t *c) { + return lsp_cell_get_function_parent_ctx(c); +} + +static inline lsp_addr_t lsp_cell_get_syntax_args(lsp_cell_t *c) { + return lsp_cell_get_function_args(c); +} + +static inline lsp_addr_t lsp_cell_get_syntax_body(lsp_cell_t *c) { + return lsp_cell_get_function_body(c); +} + +#endif diff --git a/src_c/ctx.c b/src_c/ctx.c new file mode 100644 index 0000000..693ea53 --- /dev/null +++ b/src_c/ctx.c @@ -0,0 +1,231 @@ +#include "ctx.h" +#include "function.h" +#include "syntax.h" + + +static lsp_bool_t contains_symbol(lsp_mem_t *m, lsp_addr_t ctx, + lsp_addr_t symbol) { + while (ctx != m->nil) { + lsp_addr_t entry = lsp_mem_get_pair_first(m, ctx); + lsp_addr_t entry_symbol = lsp_mem_get_pair_first(m, entry); + + if (lsp_mem_eq(m, entry_symbol, symbol)) + return true; + + ctx = lsp_mem_get_pair_second(m, ctx); + } + + return false; +} + + +static lsp_status_t remove_symbol(lsp_mem_t *m, lsp_addr_t ctx, + lsp_addr_t symbol) { + lsp_addr_t list = lsp_mem_get_pair_first(m, ctx); + + lsp_addr_t result = m->nil; + lsp_addr_t result_last = m->nil; + lsp_status_t status = LSP_SUCCESS; + + while (list != m->nil) { + lsp_addr_t entry = lsp_mem_get_pair_first(m, list); + lsp_addr_t entry_symbol = lsp_mem_get_pair_first(m, entry); + list = lsp_mem_get_pair_second(m, list); + + if (lsp_mem_eq(m, entry_symbol, symbol)) { + if (result == m->nil) { + result = list; + status = lsp_mem_inc_ref(m, list); + + } else { + lsp_mem_set_pair_second(m, result_last, list); + } + + break; + } + + lsp_addr_t new_result_last; + status = lsp_mem_create_pair(m, entry, m->nil, &new_result_last); + if (status != LSP_SUCCESS) + break; + + if (result == m->nil) { + result = new_result_last; + + } else { + lsp_mem_set_pair_second(m, result_last, new_result_last); + lsp_mem_dec_ref(m, new_result_last); + } + + result_last = new_result_last; + } + + if (status == LSP_SUCCESS) + lsp_mem_set_pair_first(m, ctx, result); + + lsp_mem_dec_ref(m, result); + return status; +} + + +lsp_status_t lsp_ctx_create(lsp_mem_t *m, lsp_addr_t *ctx) { + lsp_addr_t list = m->nil; + lsp_addr_t list_last = m->nil; + lsp_status_t status = LSP_SUCCESS; + + for (uint8_t i = 0; status == LSP_SUCCESS && lsp_syntaxes[i].name; ++i) { + lsp_addr_t symbol; + status = + lsp_mem_create_symbol_from_char(m, lsp_syntaxes[i].name, &symbol); + if (status != LSP_SUCCESS) + break; + + lsp_addr_t value; + status = lsp_mem_create_builtin_syntax(m, i, &value); + if (status != LSP_SUCCESS) { + lsp_mem_dec_ref(m, symbol); + break; + } + + lsp_addr_t entry; + status = lsp_mem_create_pair(m, symbol, value, &entry); + lsp_mem_dec_ref(m, symbol); + lsp_mem_dec_ref(m, value); + if (status != LSP_SUCCESS) + break; + + lsp_addr_t new_list_last; + status = lsp_mem_create_pair(m, entry, m->nil, &new_list_last); + lsp_mem_dec_ref(m, entry); + if (status != LSP_SUCCESS) + break; + + if (list == m->nil) { + list = new_list_last; + + } else { + lsp_mem_set_pair_second(m, list_last, new_list_last); + lsp_mem_dec_ref(m, new_list_last); + } + + list_last = new_list_last; + } + + for (uint8_t i = 0; status == LSP_SUCCESS && lsp_functions[i].name; ++i) { + lsp_addr_t symbol; + status = + lsp_mem_create_symbol_from_char(m, lsp_functions[i].name, &symbol); + if (status != LSP_SUCCESS) + break; + + lsp_addr_t value; + status = lsp_mem_create_builtin_function(m, i, &value); + if (status != LSP_SUCCESS) { + lsp_mem_dec_ref(m, symbol); + break; + } + + lsp_addr_t entry; + status = lsp_mem_create_pair(m, symbol, value, &entry); + lsp_mem_dec_ref(m, symbol); + lsp_mem_dec_ref(m, value); + if (status != LSP_SUCCESS) + break; + + lsp_addr_t new_list_last; + status = lsp_mem_create_pair(m, entry, m->nil, &new_list_last); + lsp_mem_dec_ref(m, entry); + if (status != LSP_SUCCESS) + break; + + if (list == m->nil) { + list = new_list_last; + + } else { + lsp_mem_set_pair_second(m, list_last, new_list_last); + lsp_mem_dec_ref(m, new_list_last); + } + + list_last = new_list_last; + } + + if (status == LSP_SUCCESS) + status = lsp_mem_create_pair(m, list, m->nil, ctx); + + lsp_mem_dec_ref(m, list); + return status; +} + + +lsp_status_t lsp_ctx_copy(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t *result) { + lsp_addr_t list = lsp_mem_get_pair_first(m, ctx); + return lsp_mem_create_pair(m, list, m->nil, result); +} + + +lsp_status_t lsp_ctx_add(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t symbol, + lsp_addr_t value) { + lsp_status_t status; + + if (contains_symbol(m, ctx, symbol)) { + status = remove_symbol(m, ctx, symbol); + if (status != LSP_SUCCESS) + return status; + } + + lsp_addr_t list = lsp_mem_get_pair_first(m, ctx); + + lsp_addr_t entry; + status = lsp_mem_create_pair(m, symbol, value, &entry); + if (status != LSP_SUCCESS) + return status; + + status = lsp_mem_create_pair(m, entry, list, &list); + lsp_mem_dec_ref(m, entry); + if (status != LSP_SUCCESS) + return status; + + lsp_mem_set_pair_first(m, ctx, list); + lsp_mem_dec_ref(m, list); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_ctx_set(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t symbol, + lsp_addr_t value) { + lsp_addr_t list = lsp_mem_get_pair_first(m, ctx); + + while (list != m->nil) { + lsp_addr_t entry = lsp_mem_get_pair_first(m, list); + lsp_addr_t entry_symbol = lsp_mem_get_pair_first(m, entry); + + if (lsp_mem_eq(m, symbol, entry_symbol)) { + lsp_mem_set_pair_second(m, entry, value); + return LSP_SUCCESS; + } + + list = lsp_mem_get_pair_second(m, list); + } + + return LSP_ERR_CTX; +} + + +lsp_status_t lsp_ctx_get(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t symbol, + lsp_addr_t *value) { + lsp_addr_t list = lsp_mem_get_pair_first(m, ctx); + + while (list != m->nil) { + lsp_addr_t entry = lsp_mem_get_pair_first(m, list); + lsp_addr_t entry_symbol = lsp_mem_get_pair_first(m, entry); + + if (lsp_mem_eq(m, symbol, entry_symbol)) { + *value = lsp_mem_get_pair_second(m, entry); + return lsp_mem_inc_ref(m, *value); + } + + list = lsp_mem_get_pair_second(m, list); + } + + return LSP_ERR_CTX; +} diff --git a/src_c/ctx.h b/src_c/ctx.h new file mode 100644 index 0000000..02740a0 --- /dev/null +++ b/src_c/ctx.h @@ -0,0 +1,16 @@ +#ifndef LISP16_CTX_H +#define LISP16_CTX_H + +#include "mem.h" + + +lsp_status_t lsp_ctx_create(lsp_mem_t *m, lsp_addr_t *ctx); +lsp_status_t lsp_ctx_copy(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t *result); +lsp_status_t lsp_ctx_add(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t symbol, + lsp_addr_t value); +lsp_status_t lsp_ctx_set(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t symbol, + lsp_addr_t value); +lsp_status_t lsp_ctx_get(lsp_mem_t *m, lsp_addr_t ctx, lsp_addr_t symbol, + lsp_addr_t *value); + +#endif diff --git a/src_c/env.c b/src_c/env.c new file mode 100644 index 0000000..13999d5 --- /dev/null +++ b/src_c/env.c @@ -0,0 +1,86 @@ +#include "env.h" +#include "ctx.h" +#include "eval.h" + + +static void init_result(lsp_env_t *e) { + e->result.is_value = true; + e->result.ctx = e->m->nil; + e->result.value = e->m->nil; +} + + +static void release_result(lsp_env_t *e) { + lsp_mem_dec_ref(e->m, e->result.ctx); + lsp_mem_dec_ref(e->m, e->result.value); + + init_result(e); +} + + +void lsp_env_init(lsp_env_t *e, lsp_mem_t *m, lsp_in_stream_t *in, + lsp_out_stream_t *out) { + e->m = m; + e->in = in; + e->out = out; + + init_result(e); +} + + +lsp_status_t lsp_env_set_result_value(lsp_env_t *e, lsp_addr_t value) { + release_result(e); + + lsp_status_t status = lsp_mem_inc_ref(e->m, value); + if (status != LSP_SUCCESS) + return status; + + e->result.is_value = true; + e->result.value = value; + return LSP_SUCCESS; +} + + +lsp_status_t lsp_env_set_result_eval(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t value) { + release_result(e); + + lsp_status_t status = lsp_mem_inc_ref(e->m, ctx); + if (status != LSP_SUCCESS) + return status; + + status = lsp_mem_inc_ref(e->m, value); + if (status != LSP_SUCCESS) { + lsp_mem_dec_ref(e->m, ctx); + return status; + } + + e->result.is_value = false; + e->result.ctx = ctx; + e->result.value = value; + return LSP_SUCCESS; +} + + +lsp_status_t lsp_env_resolve(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value, + lsp_addr_t *result) { + lsp_status_t status = lsp_env_set_result_eval(e, ctx, value); + if (status != LSP_SUCCESS) + return status; + + while (!e->result.is_value) { + lsp_addr_t eval_ctx = e->result.ctx; + lsp_addr_t eval_value = e->result.value; + init_result(e); + + status = lsp_eval(e, eval_ctx, eval_value); + lsp_mem_dec_ref(e->m, eval_ctx); + lsp_mem_dec_ref(e->m, eval_value); + if (status != LSP_SUCCESS) + return status; + } + + *result = e->result.value; + init_result(e); + return LSP_SUCCESS; +} diff --git a/src_c/env.h b/src_c/env.h new file mode 100644 index 0000000..026cd18 --- /dev/null +++ b/src_c/env.h @@ -0,0 +1,30 @@ +#ifndef LISP16_ENV_H +#define LISP16_ENV_H + +#include "mem.h" +#include "stream.h" + + +typedef struct { + lsp_mem_t *m; + lsp_in_stream_t *in; + lsp_out_stream_t *out; + + // internal + struct { + lsp_bool_t is_value; + lsp_addr_t ctx; + lsp_addr_t value; + } result; +} lsp_env_t; + + +void lsp_env_init(lsp_env_t *e, lsp_mem_t *m, lsp_in_stream_t *in, + lsp_out_stream_t *out); +lsp_status_t lsp_env_set_result_value(lsp_env_t *e, lsp_addr_t value); +lsp_status_t lsp_env_set_result_eval(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t value); +lsp_status_t lsp_env_resolve(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value, + lsp_addr_t *result); + +#endif diff --git a/src_c/eval.c b/src_c/eval.c new file mode 100644 index 0000000..e04537e --- /dev/null +++ b/src_c/eval.c @@ -0,0 +1,92 @@ +#include "eval.h" +#include "ctx.h" +#include "apply.h" + + +static lsp_status_t eval_args(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args, + lsp_addr_t *result) { + lsp_addr_t last = e->m->nil; + *result = e->m->nil; + lsp_status_t status; + + while (args != e->m->nil) { + lsp_addr_t arg = lsp_mem_get_pair_first(e->m, args); + status = lsp_env_resolve(e, ctx, arg, &arg); + if (status != LSP_SUCCESS) + goto error; + + lsp_addr_t new_last; + status = lsp_mem_create_pair(e->m, arg, e->m->nil, &new_last); + lsp_mem_dec_ref(e->m, arg); + if (status != LSP_SUCCESS) + goto error; + + if (*result == e->m->nil) { + *result = new_last; + + } else { + lsp_mem_set_pair_second(e->m, last, new_last); + lsp_mem_dec_ref(e->m, new_last); + } + + last = new_last; + args = lsp_mem_get_pair_second(e->m, args); + } + + return LSP_SUCCESS; + +error: + lsp_mem_dec_ref(e->m, *result); + return status; +} + + +lsp_status_t lsp_eval(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value) { + lsp_status_t status = LSP_SUCCESS; + + if (lsp_mem_is_number(e->m, value) || lsp_mem_is_string(e->m, value) || + lsp_mem_is_builtin(e->m, value) || + lsp_mem_is_function_or_syntax(e->m, value)) + return lsp_env_set_result_value(e, value); + + if (lsp_mem_is_symbol(e->m, value)) { + lsp_addr_t result; + status = lsp_ctx_get(e->m, ctx, value, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; + } + + if (lsp_mem_is_pair(e->m, value)) { + if (value == e->m->nil) + return lsp_env_set_result_value(e, e->m->nil); + + lsp_addr_t callable = lsp_mem_get_pair_first(e->m, value); + lsp_addr_t args = lsp_mem_get_pair_second(e->m, value); + + status = lsp_env_resolve(e, ctx, callable, &callable); + if (status != LSP_SUCCESS) + return status; + + if (lsp_mem_is_builtin_function(e->m, callable) || + lsp_mem_is_function(e->m, callable)) { + status = eval_args(e, ctx, args, &args); + } else { + status = lsp_mem_inc_ref(e->m, args); + } + if (status != LSP_SUCCESS) { + lsp_mem_dec_ref(e->m, callable); + return status; + } + + status = lsp_apply(e, ctx, callable, args); + lsp_mem_dec_ref(e->m, callable); + lsp_mem_dec_ref(e->m, args); + return status; + } + + return LSP_ERR_EVAL; +} diff --git a/src_c/eval.h b/src_c/eval.h new file mode 100644 index 0000000..4f40270 --- /dev/null +++ b/src_c/eval.h @@ -0,0 +1,9 @@ +#ifndef LISP16_EVAL_H +#define LISP16_EVAL_H + +#include "env.h" + + +lsp_status_t lsp_eval(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value); + +#endif diff --git a/src_c/function.c b/src_c/function.c new file mode 100644 index 0000000..075261a --- /dev/null +++ b/src_c/function.c @@ -0,0 +1,582 @@ +#include "function.h" +#include "apply.h" +#include "eval.h" +#include "read.h" +#include "write.h" + + +lsp_builtin_entry_t lsp_functions[] = { + {"eval", lsp_function_eval}, + {"apply", lsp_function_apply}, + {"error", lsp_function_error}, + {"cons", lsp_function_cons}, + {"set-car!", lsp_function_set_car}, + {"set-cdr!", lsp_function_set_cdr}, + {"number?", lsp_function_is_number}, + {"pair?", lsp_function_is_pair}, + {"string?", lsp_function_is_string}, + {"symbol?", lsp_function_is_symbol}, + {"function?", lsp_function_is_function}, + {"syntax?", lsp_function_is_syntax}, + {"eq?", lsp_function_eq}, + {"equal?", lsp_function_equal}, + {">", lsp_function_gt}, + {"<", lsp_function_lt}, + {"+", lsp_function_plus}, + {"-", lsp_function_minus}, + {"*", lsp_function_multiply}, + {"/", lsp_function_divide}, + {"read", lsp_function_read}, + {"read-u8", lsp_function_read_u8}, + {"peek-u8", lsp_function_peek_u8}, + {"write", lsp_function_write}, + {"write-u8", lsp_function_write_u8}, + {"make-string", lsp_function_make_string}, + {"string-length", lsp_function_string_length}, + {"string-ref", lsp_function_string_ref}, + {"string-set!", lsp_function_string_set}, + {NULL, NULL}}; + + +lsp_status_t lsp_function_eval(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + return lsp_eval(e, ctx, value); +} + + +lsp_status_t lsp_function_apply(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t callable; + lsp_addr_t arguments; + lsp_status_t status = + lsp_builtin_get_args_2(e->m, args, &callable, &arguments); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_builtin(e->m, callable) && + !lsp_mem_is_function_or_syntax(e->m, callable)) + return LSP_ERR_ARG_TYPE; + + return lsp_apply(e, ctx, callable, arguments); +} + + +lsp_status_t lsp_function_error(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_number(e->m, value)) + return LSP_ERR_ARG_TYPE; + + lsp_int32_t code = lsp_mem_get_number(e->m, value); + if (code < 0 || code > 126) + return LSP_ERR_ARG_VALUE; + + return LSP_ERR_USER + code; +} + + +lsp_status_t lsp_function_cons(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t first; + lsp_addr_t second; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &first, &second); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t result; + status = lsp_mem_create_pair(e->m, first, second, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_set_car(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t pair; + lsp_addr_t first; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &pair, &first); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_pair(e->m, pair)) + return LSP_ERR_ARG_TYPE; + + if (pair == e->m->nil) + return LSP_ERR_ARG_VALUE; + + lsp_mem_set_pair_first(e->m, pair, first); + return lsp_env_set_result_value(e, e->m->nil); +} + + +lsp_status_t lsp_function_set_cdr(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t pair; + lsp_addr_t second; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &pair, &second); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_pair(e->m, pair)) + return LSP_ERR_ARG_TYPE; + + if (pair == e->m->nil) + return LSP_ERR_ARG_VALUE; + + lsp_mem_set_pair_second(e->m, pair, second); + return lsp_env_set_result_value(e, e->m->nil); +} + + +lsp_status_t lsp_function_is_number(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_number = lsp_mem_is_number(e->m, value); + return lsp_env_set_result_value(e, (is_number ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_is_pair(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_pair = lsp_mem_is_pair(e->m, value); + return lsp_env_set_result_value(e, (is_pair ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_is_string(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_string = lsp_mem_is_string(e->m, value); + return lsp_env_set_result_value(e, (is_string ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_is_symbol(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_symbol = lsp_mem_is_symbol(e->m, value); + return lsp_env_set_result_value(e, (is_symbol ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_is_function(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_function = lsp_mem_is_function(e->m, value) || + lsp_mem_is_builtin_function(e->m, value); + return lsp_env_set_result_value(e, (is_function ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_is_syntax(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_syntax = lsp_mem_is_syntax(e->m, value) || + lsp_mem_is_builtin_syntax(e->m, value); + return lsp_env_set_result_value(e, (is_syntax ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_eq(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t first; + lsp_addr_t second; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &first, &second); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_eq = lsp_mem_eq(e->m, first, second); + return lsp_env_set_result_value(e, (is_eq ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_equal(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t first; + lsp_addr_t second; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &first, &second); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_equal = lsp_mem_equal(e->m, first, second); + return lsp_env_set_result_value(e, (is_equal ? e->m->one : e->m->zero)); +} + + +lsp_status_t lsp_function_gt(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t last_value = e->m->nil; + + while (args != e->m->nil) { + lsp_addr_t value = lsp_mem_get_pair_first(e->m, args); + if (!lsp_mem_is_number(e->m, value)) + return LSP_ERR_ARG_TYPE; + + if (last_value != e->m->nil && lsp_mem_get_number(e->m, last_value) <= + lsp_mem_get_number(e->m, value)) + return lsp_env_set_result_value(e, e->m->zero); + + last_value = value; + args = lsp_mem_get_pair_second(e->m, args); + } + + return lsp_env_set_result_value(e, e->m->one); +} + + +lsp_status_t lsp_function_lt(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t last_value = e->m->nil; + + while (args != e->m->nil) { + lsp_addr_t value = lsp_mem_get_pair_first(e->m, args); + if (!lsp_mem_is_number(e->m, value)) + return LSP_ERR_ARG_TYPE; + + if (last_value != e->m->nil && lsp_mem_get_number(e->m, last_value) >= + lsp_mem_get_number(e->m, value)) + return lsp_env_set_result_value(e, e->m->zero); + + last_value = value; + args = lsp_mem_get_pair_second(e->m, args); + } + + return lsp_env_set_result_value(e, e->m->one); +} + + +lsp_status_t lsp_function_plus(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_int32_t value = 0; + + while (args != e->m->nil) { + lsp_addr_t i = lsp_mem_get_pair_first(e->m, args); + if (!lsp_mem_is_number(e->m, i)) + return LSP_ERR_ARG_TYPE; + + value += lsp_mem_get_number(e->m, i); + args = lsp_mem_get_pair_second(e->m, args); + } + + lsp_addr_t result; + lsp_status_t status = lsp_mem_create_number(e->m, value, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_minus(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_int32_t value; + lsp_uint16_t counter = 0; + + while (args != e->m->nil) { + lsp_addr_t i = lsp_mem_get_pair_first(e->m, args); + if (!lsp_mem_is_number(e->m, i)) + return LSP_ERR_ARG_TYPE; + + if (++counter > 1) { + value -= lsp_mem_get_number(e->m, i); + } else { + value = lsp_mem_get_number(e->m, i); + } + + args = lsp_mem_get_pair_second(e->m, args); + } + + if (!counter) + return LSP_ERR_ARG_COUNT; + + if (counter < 2) + value = -value; + + lsp_addr_t result; + lsp_status_t status = lsp_mem_create_number(e->m, value, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_multiply(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_int32_t value = 1; + + while (args != e->m->nil) { + lsp_addr_t i = lsp_mem_get_pair_first(e->m, args); + if (!lsp_mem_is_number(e->m, i)) + return LSP_ERR_ARG_TYPE; + + value *= lsp_mem_get_number(e->m, i); + args = lsp_mem_get_pair_second(e->m, args); + } + + lsp_addr_t result; + lsp_status_t status = lsp_mem_create_number(e->m, value, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_divide(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_int32_t value; + lsp_uint16_t counter = 0; + + while (args != e->m->nil) { + lsp_addr_t i = lsp_mem_get_pair_first(e->m, args); + if (!lsp_mem_is_number(e->m, i)) + return LSP_ERR_ARG_TYPE; + + if (++counter > 1) { + value /= lsp_mem_get_number(e->m, i); + } else { + value = lsp_mem_get_number(e->m, i); + } + + args = lsp_mem_get_pair_second(e->m, args); + } + + if (!counter) + return LSP_ERR_ARG_COUNT; + + if (counter < 2) + value = 1 / value; + + lsp_addr_t result; + lsp_status_t status = lsp_mem_create_number(e->m, value, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + + +lsp_status_t lsp_function_read(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + if (args != e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t value; + lsp_status_t status = lsp_read(e->m, e->in, &value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, value); + lsp_mem_dec_ref(e->m, value); + return status; +} + + +lsp_status_t lsp_function_read_u8(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + if (args != e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_read(e->in, &c); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t result; + status = lsp_mem_create_number(e->m, c, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_peek_u8(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + if (args != e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_peek(e->in, &c); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t result; + status = lsp_mem_create_number(e->m, c, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_write(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_write(e->m, e->out, value); + if (status != LSP_SUCCESS) + return status; + + return lsp_env_set_result_value(e, e->m->nil); +} + + +lsp_status_t lsp_function_write_u8(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_number(e->m, value)) + return LSP_ERR_ARG_TYPE; + + lsp_uint8_t c = lsp_mem_get_number(e->m, value); + status = lsp_out_stream_write(e->out, c); + if (status != LSP_SUCCESS) + return status; + + return lsp_env_set_result_value(e, e->m->nil); +} + + +lsp_status_t lsp_function_make_string(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_number(e->m, value)) + return LSP_ERR_ARG_TYPE; + + lsp_uint16_t str_len = lsp_mem_get_number(e->m, value); + + lsp_addr_t result; + status = lsp_mem_create_string(e->m, str_len, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_string_length(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t str; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &str); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_string(e->m, str)) + return LSP_ERR_ARG_TYPE; + + lsp_uint16_t str_len = lsp_mem_get_string_len(e->m, str); + + lsp_addr_t result; + status = lsp_mem_create_number(e->m, str_len, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_string_ref(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t str; + lsp_addr_t index; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &str, &index); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_string(e->m, str) || !lsp_mem_is_number(e->m, index)) + return LSP_ERR_ARG_TYPE; + + lsp_uint16_t i = lsp_mem_get_number(e->m, index); + lsp_uint16_t str_len = lsp_mem_get_string_len(e->m, str); + if (i >= str_len) + return LSP_ERR_ARG_VALUE; + + lsp_uint8_t c = lsp_mem_get_string_data(e->m, str, i); + + lsp_addr_t result; + status = lsp_mem_create_number(e->m, c, &result); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_function_string_set(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args) { + lsp_addr_t str; + lsp_addr_t index; + lsp_addr_t value; + lsp_status_t status = + lsp_builtin_get_args_3(e->m, args, &str, &index, &value); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_string(e->m, str) || !lsp_mem_is_number(e->m, index) || + !lsp_mem_is_number(e->m, value)) + return LSP_ERR_ARG_TYPE; + + lsp_uint16_t i = lsp_mem_get_number(e->m, index); + lsp_uint16_t str_len = lsp_mem_get_string_len(e->m, str); + if (i >= str_len) + return LSP_ERR_ARG_VALUE; + + lsp_mem_set_string_data(e->m, str, i, lsp_mem_get_number(e->m, value)); + + return lsp_env_set_result_value(e, e->m->nil); +} diff --git a/src_c/function.h b/src_c/function.h new file mode 100644 index 0000000..ce249c4 --- /dev/null +++ b/src_c/function.h @@ -0,0 +1,54 @@ +#ifndef LISP16_FUNCTION_H +#define LISP16_FUNCTION_H + +#include "builtin.h" + + +extern lsp_builtin_entry_t lsp_functions[]; + +lsp_status_t lsp_function_eval(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_apply(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_error(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_cons(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_set_car(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_set_cdr(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_is_number(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_is_pair(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_is_string(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_is_symbol(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_is_function(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_is_syntax(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_eq(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_equal(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_gt(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_lt(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_plus(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_minus(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_multiply(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_divide(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_read(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_read_u8(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_peek_u8(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_write(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_function_write_u8(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_make_string(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_string_length(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_string_ref(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); +lsp_status_t lsp_function_string_set(lsp_env_t *e, lsp_addr_t ctx, + lsp_addr_t args); + +#endif diff --git a/src_c/main.c b/src_c/main.c new file mode 100644 index 0000000..c09a38b --- /dev/null +++ b/src_c/main.c @@ -0,0 +1,55 @@ +#include "ctx.h" +#include "repl.h" + +#if LSP_ARCH == LSP_ARCH_POSIX +#include "arch/posix.h" +#elif LSP_ARCH == LSP_ARCH_AVR8 +#include "arch/avr8.h" +#elif LSP_ARCH == LSP_ARCH_STM32 +#include "arch/stm32.h" +#endif + + +int main() { + lsp_mem_t *m = NULL; + lsp_in_stream_t *in = NULL; + lsp_out_stream_t *out = NULL; + lsp_status_t status = LSP_ERR; + + LSP_ARCH_INIT(); + + m = LSP_ARCH_CREATE_MEM(); + if (!m) + goto cleanup; + + in = LSP_ARCH_CREATE_IN_STREAM(); + if (!in) + goto cleanup; + + out = LSP_ARCH_CREATE_OUT_STREAM(); + if (!out) + goto cleanup; + + lsp_env_t e; + lsp_env_init(&e, m, in, out); + + lsp_addr_t ctx; + status = lsp_ctx_create(m, &ctx); + if (status != LSP_SUCCESS) + goto cleanup; + + status = lsp_repl(&e, ctx); + lsp_mem_dec_ref(m, ctx); + +cleanup: + if (out) + LSP_ARCH_FREE_OUT_STREAM(out); + + if (in) + LSP_ARCH_FREE_IN_STREAM(in); + + if (m) + LSP_ARCH_FREE_MEM(m); + + return ((status == LSP_EOF) ? 0 : 1); +} diff --git a/src_c/mem.c b/src_c/mem.c new file mode 100644 index 0000000..31ca83d --- /dev/null +++ b/src_c/mem.c @@ -0,0 +1,478 @@ +#include "mem.h" + + +static inline lsp_bool_t get_mark(lsp_cell_t *c) { + return ((*c & 0x8000) ? true : false); +} + + +static inline void set_mark(lsp_cell_t *c, lsp_bool_t mark) { + if (mark) { + *c |= 0x8000; + } else { + *c &= 0x7fff; + } +} + + +static void restore(lsp_mem_t *m, lsp_addr_t addr) { + while (true) { + lsp_cell_t *c = m->cells + addr; + if (!get_mark(c)) + break; + + lsp_uint16_t c_size = lsp_cell_get_size(c); + for (lsp_uint16_t i = 0; i < c_size; ++i) + set_mark(c + i, false); + + if (lsp_cell_is_pair(c)) { + restore(m, lsp_cell_get_pair_first(c)); + addr = lsp_cell_get_pair_second(c); + + } else if (lsp_cell_is_function(c)) { + restore(m, lsp_cell_get_function_parent_ctx(c)); + restore(m, lsp_cell_get_function_args(c)); + addr = lsp_cell_get_function_body(c); + + } else if (lsp_cell_is_syntax(c)) { + restore(m, lsp_cell_get_syntax_parent_ctx(c)); + restore(m, lsp_cell_get_syntax_args(c)); + addr = lsp_cell_get_syntax_body(c); + } + } +} + + +static void mark_and_restore(lsp_mem_t *m) { + for (lsp_addr_t addr = 0; addr < m->size; ++addr) + set_mark(m->cells + addr, true); + + restore(m, m->nil); + restore(m, m->zero); + restore(m, m->one); + restore(m, m->quote); + restore(m, m->quasiquote); + restore(m, m->unquote); + restore(m, m->unquote_splicing); + restore(m, m->root); +} + + +static lsp_bool_t is_free_cell(lsp_mem_t *m, lsp_addr_t addr, lsp_uint16_t size, + lsp_addr_t *used_addr) { + for (lsp_addr_t i = addr; i < addr + size; ++i) { + if (!get_mark(m->cells + i)) { + *used_addr = i; + return false; + } + } + + return true; +} + + +static lsp_status_t find_free_cell(lsp_mem_t *m, lsp_uint16_t size, + lsp_addr_t *addr) { + if (!size) + return LSP_ERR_MEM; + + for (lsp_addr_t i = m->last_addr; i < m->size - size; ++i) { + if (is_free_cell(m, i, size, &i)) { + *addr = i; + m->last_addr = i; + return LSP_SUCCESS; + } + } + + for (lsp_addr_t i = 0; i < m->last_addr && i < m->size - size; ++i) { + if (is_free_cell(m, i, size, &i)) { + *addr = i; + m->last_addr = i; + return LSP_SUCCESS; + } + } + + return LSP_ERR_MEM; +} + + +static lsp_status_t find_free_cell_with_gc(lsp_mem_t *m, lsp_uint16_t size, + lsp_addr_t *addr) { + lsp_status_t status = find_free_cell(m, size, addr); + if (status == LSP_SUCCESS) + return LSP_SUCCESS; + + mark_and_restore(m); + + return find_free_cell(m, size, addr); +} + + +static lsp_status_t alloc_cell(lsp_mem_t *m, lsp_uint16_t size, + lsp_addr_t *addr) { + lsp_addr_t root; + lsp_status_t status = find_free_cell_with_gc(m, 2, &root); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_pair(m->cells + root, m->nil, m->root); + m->root = root; + + status = find_free_cell_with_gc(m, size, addr); + if (status != LSP_SUCCESS) { + m->root = lsp_cell_get_pair_second(m->cells + root); + return status; + } + + lsp_mem_set_pair_first(m, root, *addr); + return LSP_SUCCESS; +} + + +static lsp_bool_t is_symbol_from_string(lsp_mem_t *m, lsp_addr_t symbol, + lsp_addr_t str) { + lsp_uint16_t str_len = lsp_cell_get_string_len(m->cells + str); + if (lsp_mem_get_symbol_len(m, symbol) != str_len) + return false; + + for (lsp_uint16_t i = 0; i < str_len; ++i) + if (lsp_mem_get_symbol_name(m, symbol, i) != + lsp_mem_get_string_data(m, str, i)) + return false; + + return true; +} + + +static lsp_bool_t is_symbol_from_char(lsp_mem_t *m, lsp_addr_t symbol, + char *name, lsp_uint16_t name_len) { + if (lsp_mem_get_symbol_len(m, symbol) != name_len) + return false; + + for (lsp_uint16_t i = 0; i < name_len; ++i) + if (lsp_mem_get_symbol_name(m, symbol, i) != name[i]) + return false; + + return true; +} + + +static lsp_status_t find_symbol_from_string(lsp_mem_t *m, lsp_addr_t str, + lsp_addr_t *addr) { + for (lsp_addr_t i = 0; i < m->size; ++i) { + if (get_mark(m->cells + i)) + continue; + + if (lsp_cell_is_symbol(m->cells + i) && + is_symbol_from_string(m, i, str)) { + *addr = i; + return LSP_SUCCESS; + } + + i += lsp_cell_get_size(m->cells + i) - 1; + } + + return LSP_ERR; +} + + +static lsp_status_t find_symbol_from_char(lsp_mem_t *m, char *name, + lsp_uint16_t name_len, + lsp_addr_t *addr) { + for (lsp_addr_t i = 0; i < m->size; ++i) { + if (get_mark(m->cells + i)) + continue; + + if (lsp_cell_is_symbol(m->cells + i) && + is_symbol_from_char(m, i, name, name_len)) { + *addr = i; + return LSP_SUCCESS; + } + + i += lsp_cell_get_size(m->cells + i) - 1; + } + + return LSP_ERR; +} + + +lsp_status_t lsp_mem_init(lsp_mem_t *m, lsp_uint16_t size) { + m->size = size; + m->last_addr = 0; + + for (lsp_addr_t addr = 0; addr < size; ++addr) + set_mark(m->cells + addr, true); + + lsp_status_t status = find_free_cell(m, 2, &(m->nil)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_pair(m->cells + m->nil, m->nil, m->nil); + + status = find_free_cell(m, lsp_cell_get_number_size(0), &(m->zero)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_number(m->cells + m->zero, 0); + + status = find_free_cell(m, lsp_cell_get_number_size(1), &(m->one)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_number(m->cells + m->one, 1); + + status = find_free_cell(m, lsp_cell_get_string_symbol_size(5), &(m->quote)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_symbol(m->cells + m->quote, 5); + for (lsp_uint16_t i = 0; i < 5; ++i) + lsp_cell_set_symbol_name(m->cells + m->quote, i, ("quote")[i]); + + status = find_free_cell(m, lsp_cell_get_string_symbol_size(10), + &(m->quasiquote)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_symbol(m->cells + m->quasiquote, 10); + for (lsp_uint16_t i = 0; i < 10; ++i) + lsp_cell_set_symbol_name(m->cells + m->quasiquote, i, + ("quasiquote")[i]); + + status = + find_free_cell(m, lsp_cell_get_string_symbol_size(7), &(m->unquote)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_symbol(m->cells + m->unquote, 7); + for (lsp_uint16_t i = 0; i < 7; ++i) + lsp_cell_set_symbol_name(m->cells + m->unquote, i, ("unquote")[i]); + + status = find_free_cell(m, lsp_cell_get_string_symbol_size(16), + &(m->unquote_splicing)); + if (status != LSP_SUCCESS) + return status; + lsp_cell_set_symbol(m->cells + m->unquote_splicing, 16); + for (lsp_uint16_t i = 0; i < 16; ++i) + lsp_cell_set_symbol_name(m->cells + m->unquote_splicing, i, + ("unquote-splicing")[i]); + + m->root = m->nil; + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_inc_ref(lsp_mem_t *m, lsp_addr_t addr) { + if (addr == m->nil || addr == m->zero || addr == m->one || addr == m->quote) + return LSP_SUCCESS; + + lsp_addr_t root; + lsp_status_t status = find_free_cell_with_gc(m, 2, &root); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_pair(m->cells + root, addr, m->root); + m->root = root; + return LSP_SUCCESS; +} + + +void lsp_mem_dec_ref(lsp_mem_t *m, lsp_addr_t addr) { + if (addr == m->nil || addr == m->zero || addr == m->one || addr == m->quote) + return; + + lsp_addr_t curr_addr = m->root; + lsp_addr_t prev_addr = m->nil; + while (curr_addr != m->nil) { + lsp_addr_t first = lsp_cell_get_pair_first(m->cells + curr_addr); + lsp_addr_t second = lsp_cell_get_pair_second(m->cells + curr_addr); + + if (first == addr) { + if (prev_addr == m->nil) { + m->root = second; + + } else { + lsp_mem_set_pair_second(m, prev_addr, second); + } + + return; + } + + prev_addr = curr_addr; + curr_addr = second; + } +} + + +lsp_status_t lsp_mem_create_number(lsp_mem_t *m, lsp_int32_t value, + lsp_addr_t *addr) { + lsp_uint16_t size = lsp_cell_get_number_size(value); + lsp_status_t status = alloc_cell(m, size, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_number(m->cells + *addr, value); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_pair(lsp_mem_t *m, lsp_addr_t first, + lsp_addr_t second, lsp_addr_t *addr) { + lsp_status_t status = alloc_cell(m, 2, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_pair(m->cells + *addr, first, second); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_string(lsp_mem_t *m, lsp_uint16_t data_len, + lsp_addr_t *addr) { + lsp_uint16_t size = lsp_cell_get_string_symbol_size(data_len); + lsp_status_t status = alloc_cell(m, size, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_string(m->cells + *addr, data_len); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_symbol_from_string(lsp_mem_t *m, lsp_addr_t str, + lsp_addr_t *addr) { + if (find_symbol_from_string(m, str, addr) == LSP_SUCCESS) + return lsp_mem_inc_ref(m, *addr); + + lsp_uint16_t name_len = lsp_mem_get_string_len(m, str); + lsp_uint16_t size = lsp_cell_get_string_symbol_size(name_len); + lsp_status_t status = alloc_cell(m, size, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_symbol(m->cells + *addr, name_len); + for (lsp_uint16_t i = 0; i < name_len; ++i) + lsp_cell_set_symbol_name(m->cells + *addr, i, + lsp_mem_get_string_data(m, str, i)); + + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_symbol_from_char(lsp_mem_t *m, char *name, + lsp_addr_t *addr) { + lsp_uint16_t name_len = 0; + while (name[name_len]) + name_len++; + + if (find_symbol_from_char(m, name, name_len, addr) == LSP_SUCCESS) + return lsp_mem_inc_ref(m, *addr); + + lsp_uint16_t size = lsp_cell_get_string_symbol_size(name_len); + lsp_status_t status = alloc_cell(m, size, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_symbol(m->cells + *addr, name_len); + for (lsp_uint16_t i = 0; i < name_len; ++i) + lsp_cell_set_symbol_name(m->cells + *addr, i, name[i]); + + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_builtin_function(lsp_mem_t *m, lsp_uint16_t index, + lsp_addr_t *addr) { + lsp_status_t status = alloc_cell(m, 1, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_builtin_function(m->cells + *addr, index); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_builtin_syntax(lsp_mem_t *m, lsp_uint16_t index, + lsp_addr_t *addr) { + lsp_status_t status = alloc_cell(m, 1, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_builtin_syntax(m->cells + *addr, index); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_function(lsp_mem_t *m, lsp_addr_t parent_ctx, + lsp_addr_t args, lsp_addr_t body, + lsp_addr_t *addr) { + lsp_status_t status = alloc_cell(m, 4, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_function(m->cells + *addr, parent_ctx, args, body); + return LSP_SUCCESS; +} + + +lsp_status_t lsp_mem_create_syntax(lsp_mem_t *m, lsp_addr_t parent_ctx, + lsp_addr_t args, lsp_addr_t body, + lsp_addr_t *addr) { + lsp_status_t status = alloc_cell(m, 4, addr); + if (status != LSP_SUCCESS) + return status; + + lsp_cell_set_syntax(m->cells + *addr, parent_ctx, args, body); + return LSP_SUCCESS; +} + + +lsp_bool_t lsp_mem_eq(lsp_mem_t *m, lsp_addr_t a1, lsp_addr_t a2) { + if (a1 == a2) + return true; + + if (lsp_mem_is_number(m, a1)) { + if (!lsp_mem_is_number(m, a2)) + return false; + + return lsp_mem_get_number(m, a1) == lsp_mem_get_number(m, a2); + } + + return false; +} + + +lsp_bool_t lsp_mem_equal(lsp_mem_t *m, lsp_addr_t a1, lsp_addr_t a2) { + if (lsp_mem_eq(m, a1, a2)) + return true; + + if (lsp_mem_is_pair(m, a1)) { + if (!lsp_mem_is_pair(m, a2)) + return false; + + while (a1 != m->nil && a2 != m->nil) { + if (!lsp_mem_equal(m, lsp_mem_get_pair_first(m, a1), + lsp_mem_get_pair_first(m, a2))) + return false; + + a1 = lsp_mem_get_pair_second(m, a1); + a2 = lsp_mem_get_pair_second(m, a2); + } + + return a1 == a2; + } + + if (lsp_mem_is_string(m, a1)) { + if (!lsp_mem_is_string(m, a2)) + return false; + + lsp_uint16_t a1_len = lsp_mem_get_string_len(m, a1); + lsp_uint16_t a2_len = lsp_mem_get_string_len(m, a2); + if (a1_len != a2_len) + return false; + + for (lsp_uint16_t i = 0; i < a1_len; ++i) { + if (lsp_mem_get_string_data(m, a1, i) != + lsp_mem_get_string_data(m, a2, i)) + return false; + } + + return true; + } + + return false; +} diff --git a/src_c/mem.h b/src_c/mem.h new file mode 100644 index 0000000..7d72ba9 --- /dev/null +++ b/src_c/mem.h @@ -0,0 +1,189 @@ +#ifndef LISP16_MEM_H +#define LISP16_MEM_H + +#include "cell.h" +#include "status.h" + + +typedef struct { + lsp_addr_t nil; + lsp_addr_t zero; + lsp_addr_t one; + lsp_addr_t quote; + lsp_addr_t quasiquote; + lsp_addr_t unquote; + lsp_addr_t unquote_splicing; + + // internal + lsp_uint16_t size; + lsp_addr_t last_addr; + lsp_addr_t root; + lsp_cell_t cells[]; +} lsp_mem_t; + + +lsp_status_t lsp_mem_init(lsp_mem_t *m, lsp_uint16_t size); +lsp_status_t lsp_mem_inc_ref(lsp_mem_t *m, lsp_addr_t addr); +void lsp_mem_dec_ref(lsp_mem_t *m, lsp_addr_t addr); + +lsp_status_t lsp_mem_create_number(lsp_mem_t *m, lsp_int32_t value, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_pair(lsp_mem_t *m, lsp_addr_t first, + lsp_addr_t second, lsp_addr_t *addr); +lsp_status_t lsp_mem_create_string(lsp_mem_t *m, lsp_uint16_t data_len, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_symbol_from_string(lsp_mem_t *m, lsp_addr_t str, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_symbol_from_char(lsp_mem_t *m, char *name, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_builtin_function(lsp_mem_t *m, lsp_uint16_t index, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_builtin_syntax(lsp_mem_t *m, lsp_uint16_t index, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_function(lsp_mem_t *m, lsp_addr_t parent_ctx, + lsp_addr_t args, lsp_addr_t body, + lsp_addr_t *addr); +lsp_status_t lsp_mem_create_syntax(lsp_mem_t *m, lsp_addr_t parent_ctx, + lsp_addr_t args, lsp_addr_t body, + lsp_addr_t *addr); + +lsp_bool_t lsp_mem_eq(lsp_mem_t *m, lsp_addr_t a1, lsp_addr_t a2); +lsp_bool_t lsp_mem_equal(lsp_mem_t *m, lsp_addr_t a1, lsp_addr_t a2); + + +static inline lsp_bool_t lsp_mem_is_number(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_number(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_pair(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_pair(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_string(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_string(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_symbol(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_symbol(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_builtin_function(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_is_builtin_function(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_builtin_syntax(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_is_builtin_syntax(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_function(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_function(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_syntax(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_syntax(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_string_or_symbol(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_is_string_or_symbol(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_builtin(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_is_builtin(m->cells + addr); +} + +static inline lsp_bool_t lsp_mem_is_function_or_syntax(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_is_function_or_syntax(m->cells + addr); +} + + +static inline lsp_int32_t lsp_mem_get_number(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_get_number(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_pair_first(lsp_mem_t *m, lsp_addr_t addr) { + return lsp_cell_get_pair_first(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_pair_second(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_pair_second(m->cells + addr); +} + +static inline lsp_uint16_t lsp_mem_get_string_len(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_string_len(m->cells + addr); +} + +static inline lsp_uint8_t lsp_mem_get_string_data(lsp_mem_t *m, lsp_addr_t addr, + lsp_uint16_t i) { + return lsp_cell_get_string_data(m->cells + addr, i); +} + +static inline lsp_uint16_t lsp_mem_get_symbol_len(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_symbol_len(m->cells + addr); +} + +static inline lsp_uint8_t lsp_mem_get_symbol_name(lsp_mem_t *m, lsp_addr_t addr, + lsp_uint16_t i) { + return lsp_cell_get_symbol_name(m->cells + addr, i); +} + +static inline lsp_uint16_t lsp_mem_get_builtin_index(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_builtin_index(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_function_parent_ctx(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_function_parent_ctx(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_function_args(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_function_args(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_function_body(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_function_body(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_syntax_parent_ctx(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_syntax_parent_ctx(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_syntax_args(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_syntax_args(m->cells + addr); +} + +static inline lsp_addr_t lsp_mem_get_syntax_body(lsp_mem_t *m, + lsp_addr_t addr) { + return lsp_cell_get_syntax_body(m->cells + addr); +} + + +static inline void lsp_mem_set_pair_first(lsp_mem_t *m, lsp_addr_t addr, + lsp_addr_t first) { + lsp_cell_set_pair(m->cells + addr, first, + lsp_cell_get_pair_second(m->cells + addr)); +} + +static inline void lsp_mem_set_pair_second(lsp_mem_t *m, lsp_addr_t addr, + lsp_addr_t second) { + lsp_cell_set_pair(m->cells + addr, lsp_cell_get_pair_first(m->cells + addr), + second); +} + +static inline void lsp_mem_set_string_data(lsp_mem_t *m, lsp_addr_t addr, + lsp_uint16_t i, lsp_uint8_t data_i) { + lsp_cell_set_string_data(m->cells + addr, i, data_i); +} + +#endif diff --git a/src_c/read.c b/src_c/read.c new file mode 100644 index 0000000..82250f5 --- /dev/null +++ b/src_c/read.c @@ -0,0 +1,428 @@ +#include "read.h" +#include "buff.h" + + +static inline lsp_bool_t is_ws(lsp_uint8_t v) { + return (v == ' ') || (v == '\n') || (v == '\r') || (v == '\t'); +} + + +static inline lsp_bool_t is_comment_start(lsp_uint8_t v) { return v == ';'; } + + +static inline lsp_bool_t is_comment_stop(lsp_uint8_t v) { return v == '\n'; } + + +static inline lsp_bool_t is_digit(lsp_uint8_t v) { + return (v >= '0') && (v <= '9'); +} + + +static inline lsp_bool_t is_list_start(lsp_uint8_t v) { + return (v == '(') || (v == '[') || (v == '{'); +} + + +static inline lsp_bool_t is_list_stop(lsp_uint8_t v) { + return (v == ')') || (v == ']') || (v == '}'); +} + + +static inline lsp_bool_t is_str_start_stop(lsp_uint8_t v) { return v == '"'; } + + +static inline lsp_bool_t is_quote(lsp_uint8_t v) { return v == '\''; } + + +static inline lsp_bool_t is_quasiquote(lsp_uint8_t v) { return v == '`'; } + + +static inline lsp_bool_t is_unquote(lsp_uint8_t v) { return v == ','; } + + +static lsp_status_t skip_ws(lsp_in_stream_t *s) { + while (true) { + lsp_uint8_t v; + lsp_status_t status = lsp_in_stream_peek(s, &v); + if (status != LSP_SUCCESS) + return status; + + if (is_comment_start(v)) { + while (!is_comment_stop(v)) { + status = lsp_in_stream_read(s, &v); + if (status != LSP_SUCCESS) + return status; + } + + continue; + } + + if (!is_ws(v)) + return LSP_SUCCESS; + + lsp_in_stream_read(s, &v); + } +} + + +static lsp_status_t read_number(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_int32_t v = 0; + + while (true) { + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_peek(s, &c); + if (status != LSP_SUCCESS) + return status; + + if (is_ws(c) || is_list_start(c) || is_list_stop(c)) + break; + + if (!is_digit(c)) + return LSP_ERR_READ; + + status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + + v = (v * 10) + (c - '0'); + } + + if (v == 0) { + *addr = m->zero; + return LSP_SUCCESS; + } + + if (v == 1) { + *addr = m->one; + return LSP_SUCCESS; + } + + return lsp_mem_create_number(m, v, addr); +} + + +static lsp_status_t read_list(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + + lsp_uint8_t list_end; + if (c == '(') { + list_end = ')'; + } else if (c == '[') { + list_end = ']'; + } else if (c == '{') { + list_end = '}'; + } else { + return LSP_ERR_READ; + } + + lsp_bool_t read_rest = false; + lsp_bool_t read_stop = false; + lsp_addr_t rest = m->nil; + lsp_addr_t last = m->nil; + *addr = m->nil; + + while (true) { + status = skip_ws(s); + if (status != LSP_SUCCESS) + break; + + status = lsp_in_stream_peek(s, &c); + if (status != LSP_SUCCESS) + break; + + if (is_list_stop(c)) { + status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + break; + + if (c != list_end) { + status = LSP_ERR_READ; + break; + } + + lsp_mem_set_pair_second(m, last, rest); + lsp_mem_dec_ref(m, rest); + return LSP_SUCCESS; + } + + if (read_stop) { + status = LSP_ERR_READ; + break; + } + + lsp_addr_t el; + status = lsp_read(m, s, &el); + if (status != LSP_SUCCESS) + break; + + if (lsp_mem_is_symbol(m, el) && lsp_mem_get_symbol_len(m, el) == 1 && + lsp_mem_get_symbol_name(m, el, 0) == '.') { + lsp_mem_dec_ref(m, el); + + if (read_rest) { + status = LSP_ERR_READ; + break; + } + + read_rest = true; + continue; + } + + if (read_rest) { + rest = el; + read_stop = true; + continue; + } + + lsp_addr_t new_last; + status = lsp_mem_create_pair(m, el, m->nil, &new_last); + lsp_mem_dec_ref(m, el); + if (status != LSP_SUCCESS) + break; + + lsp_mem_set_pair_second(m, last, new_last); + last = new_last; + + if (*addr == m->nil) { + *addr = last; + } else { + lsp_mem_dec_ref(m, last); + } + } + + lsp_mem_dec_ref(m, *addr); + lsp_mem_dec_ref(m, rest); + return status; +} + + +static lsp_status_t read_string(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + + if (!is_str_start_stop(c)) + return LSP_ERR_READ; + + lsp_buff_t buff; + lsp_buff_init(&buff, m); + + lsp_bool_t read_escaped = false; + + while (true) { + status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + goto cleanup; + + if (read_escaped) { + if (c == 'n') { + status = lsp_buff_push(&buff, '\n'); + } else if (c == 'r') { + status = lsp_buff_push(&buff, '\r'); + } else if (c == 't') { + status = lsp_buff_push(&buff, '\t'); + } else if (c == '\\') { + status = lsp_buff_push(&buff, '\\'); + } else if (c == '"') { + status = lsp_buff_push(&buff, '"'); + } else { + status = LSP_ERR_READ; + } + + if (status != LSP_SUCCESS) + goto cleanup; + + read_escaped = false; + continue; + } + + if (c == '\\') { + read_escaped = true; + continue; + } + + if (is_str_start_stop(c)) + break; + + status = lsp_buff_push(&buff, c); + if (status != LSP_SUCCESS) + goto cleanup; + } + + status = lsp_buff_pop(&buff, addr); + +cleanup: + lsp_buff_clear(&buff); + return status; +} + + +static lsp_status_t read_quote(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + + if (!is_quote(c)) + return LSP_ERR_READ; + + lsp_addr_t value; + status = lsp_read(m, s, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t list; + status = lsp_mem_create_pair(m, value, m->nil, &list); + lsp_mem_dec_ref(m, value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_mem_create_pair(m, m->quote, list, addr); + lsp_mem_dec_ref(m, list); + return status; +} + + +static lsp_status_t read_quasiquote(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + + if (!is_quasiquote(c)) + return LSP_ERR_READ; + + lsp_addr_t value; + status = lsp_read(m, s, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t list; + status = lsp_mem_create_pair(m, value, m->nil, &list); + lsp_mem_dec_ref(m, value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_mem_create_pair(m, m->quasiquote, list, addr); + lsp_mem_dec_ref(m, list); + return status; +} + + +static lsp_status_t read_unquote(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_uint8_t c; + lsp_status_t status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + + if (!is_unquote(c)) + return LSP_ERR_READ; + + status = lsp_in_stream_peek(s, &c); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_splicing = (c == '@'); + if (is_splicing) { + status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + return status; + } + + lsp_addr_t value; + status = lsp_read(m, s, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t list; + status = lsp_mem_create_pair(m, value, m->nil, &list); + lsp_mem_dec_ref(m, value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_mem_create_pair( + m, (is_splicing ? m->unquote_splicing : m->unquote), list, addr); + lsp_mem_dec_ref(m, list); + return status; +} + + +static lsp_status_t read_symbol(lsp_mem_t *m, lsp_in_stream_t *s, + lsp_addr_t *addr) { + lsp_status_t status; + + lsp_buff_t buff; + lsp_buff_init(&buff, m); + + while (true) { + lsp_uint8_t c; + status = lsp_in_stream_peek(s, &c); + if (status != LSP_SUCCESS) + goto cleanup; + + if (is_ws(c) || is_list_start(c) || is_list_stop(c)) + break; + + status = lsp_in_stream_read(s, &c); + if (status != LSP_SUCCESS) + goto cleanup; + + status = lsp_buff_push(&buff, c); + if (status != LSP_SUCCESS) + goto cleanup; + } + + lsp_addr_t str; + status = lsp_buff_pop(&buff, &str); + if (status != LSP_SUCCESS) + goto cleanup; + + status = lsp_mem_create_symbol_from_string(m, str, addr); + lsp_mem_dec_ref(m, str); + +cleanup: + lsp_buff_clear(&buff); + return status; +} + + +lsp_status_t lsp_read(lsp_mem_t *m, lsp_in_stream_t *s, lsp_addr_t *addr) { + lsp_status_t status = skip_ws(s); + if (status != LSP_SUCCESS) + return status; + + lsp_uint8_t c; + status = lsp_in_stream_peek(s, &c); + if (status != LSP_SUCCESS) + return status; + + if (is_list_start(c)) + return read_list(m, s, addr); + + if (is_str_start_stop(c)) + return read_string(m, s, addr); + + if (is_digit(c)) + return read_number(m, s, addr); + + if (is_quote(c)) + return read_quote(m, s, addr); + + if (is_quasiquote(c)) + return read_quasiquote(m, s, addr); + + if (is_unquote(c)) + return read_unquote(m, s, addr); + + return read_symbol(m, s, addr); +} diff --git a/src_c/read.h b/src_c/read.h new file mode 100644 index 0000000..15bfb7d --- /dev/null +++ b/src_c/read.h @@ -0,0 +1,10 @@ +#ifndef LISP16_READ_H +#define LISP16_READ_H + +#include "mem.h" +#include "stream.h" + + +lsp_status_t lsp_read(lsp_mem_t *m, lsp_in_stream_t *s, lsp_addr_t *addr); + +#endif diff --git a/src_c/repl.c b/src_c/repl.c new file mode 100644 index 0000000..6563613 --- /dev/null +++ b/src_c/repl.c @@ -0,0 +1,104 @@ +#include "repl.h" +#include "ctx.h" +#include "write.h" +#include "read.h" +#include "eval.h" + + +static void log_status(lsp_out_stream_t *s, lsp_status_t status) { + if (status == LSP_SUCCESS) + return; + + lsp_out_stream_write_str(s, "error: "); + + if (status == LSP_ERR_MEM) { + lsp_out_stream_write_str(s, "no memory"); + + } else if (status == LSP_ERR_CTX) { + lsp_out_stream_write_str(s, "can't resolve symbol"); + + } else if (status == LSP_ERR_READ) { + lsp_out_stream_write_str(s, "reader error"); + + } else if (status == LSP_ERR_WRITE) { + lsp_out_stream_write_str(s, "writer error"); + + } else if (status == LSP_ERR_EVAL) { + lsp_out_stream_write_str(s, "evaluation error"); + + } else if (status == LSP_ERR_APPLY) { + lsp_out_stream_write_str(s, "application error"); + + } else if (status == LSP_ERR_ARG_COUNT) { + lsp_out_stream_write_str(s, "invalid argument count"); + + } else if (status == LSP_ERR_ARG_TYPE) { + lsp_out_stream_write_str(s, "invalid argument type"); + + } else if (status == LSP_ERR_ARG_VALUE) { + lsp_out_stream_write_str(s, "invalid argument value"); + + } else if (status >= LSP_ERR_USER) { + lsp_out_stream_write_str(s, "user error "); + lsp_out_stream_write_int(s, status - LSP_ERR_USER); + + } else { + lsp_out_stream_write_str(s, "other error"); + } + + lsp_out_stream_write(s, '\n'); +} + + +static lsp_status_t skip_line(lsp_in_stream_t *s) { + lsp_uint8_t c; + lsp_status_t status; + + do { + status = lsp_in_stream_read(s, &c); + } while (status == LSP_SUCCESS && c != '\n'); + + return status; +} + + +lsp_status_t lsp_repl(lsp_env_t *e, lsp_addr_t ctx) { + while (true) { + lsp_addr_t value; + lsp_status_t status = lsp_read(e->m, e->in, &value); + if (status == LSP_EOF) + return status; + if (status != LSP_SUCCESS) { + log_status(e->out, status); + + status = skip_line(e->in); + if (status != LSP_SUCCESS) + return status; + + continue; + } + + lsp_addr_t result; + status = lsp_env_resolve(e, ctx, value, &result); + lsp_mem_dec_ref(e->m, value); + if (status == LSP_EOF) + return status; + if (status != LSP_SUCCESS) { + log_status(e->out, status); + continue; + } + + if (result == e->m->nil) + continue; + + status = lsp_write(e->m, e->out, result); + lsp_mem_dec_ref(e->m, result); + if (status == LSP_EOF) + return status; + if (status != LSP_SUCCESS) { + log_status(e->out, status); + continue; + } + lsp_out_stream_write(e->out, '\n'); + } +} diff --git a/src_c/repl.h b/src_c/repl.h new file mode 100644 index 0000000..9c34070 --- /dev/null +++ b/src_c/repl.h @@ -0,0 +1,9 @@ +#ifndef LISP16_REPL_H +#define LISP16_REPL_H + +#include "env.h" + + +lsp_status_t lsp_repl(lsp_env_t *e, lsp_addr_t ctx); + +#endif diff --git a/src_c/status.h b/src_c/status.h new file mode 100644 index 0000000..c6332e9 --- /dev/null +++ b/src_c/status.h @@ -0,0 +1,25 @@ +#ifndef LSP_STATUS_H +#define LSP_STATUS_H + +#include "arch.h" + +#define LSP_STATUS(x) ((lsp_status_t)x) + +#define LSP_SUCCESS LSP_STATUS(0) +#define LSP_EOF LSP_STATUS(-1) +#define LSP_ERR LSP_STATUS(1) +#define LSP_ERR_MEM LSP_STATUS(2) +#define LSP_ERR_CTX LSP_STATUS(3) +#define LSP_ERR_READ LSP_STATUS(4) +#define LSP_ERR_WRITE LSP_STATUS(5) +#define LSP_ERR_EVAL LSP_STATUS(6) +#define LSP_ERR_APPLY LSP_STATUS(7) +#define LSP_ERR_ARG_COUNT LSP_STATUS(8) +#define LSP_ERR_ARG_TYPE LSP_STATUS(9) +#define LSP_ERR_ARG_VALUE LSP_STATUS(10) +#define LSP_ERR_USER LSP_STATUS(0x80) + + +typedef lsp_int8_t lsp_status_t; + +#endif diff --git a/src_c/stream.c b/src_c/stream.c new file mode 100644 index 0000000..37f5d3d --- /dev/null +++ b/src_c/stream.c @@ -0,0 +1,108 @@ +#include "stream.h" + + +static lsp_int16_t str_getchar(lsp_in_stream_t *s) { + lsp_str_stream_t *ss = (lsp_str_stream_t *)s; + + if (ss->pos >= lsp_mem_get_string_len(ss->m, ss->str)) + return LSP_EOF; + + return lsp_mem_get_string_data(ss->m, ss->str, ss->pos++); +} + + +void lsp_in_stream_init(lsp_in_stream_t *s, lsp_stream_getchar_t getchar) { + s->getchar = getchar; + s->next_available = false; +} + + +lsp_status_t lsp_in_stream_read(lsp_in_stream_t *s, lsp_uint8_t *v) { + if (s->next_available) { + s->next_available = false; + *v = s->next_value; + return s->next_status; + } + + lsp_int16_t c = s->getchar(s); + *v = c; + return ((c == LSP_EOF) ? LSP_EOF : LSP_SUCCESS); +} + + +lsp_status_t lsp_in_stream_peek(lsp_in_stream_t *s, lsp_uint8_t *v) { + if (s->next_available) { + *v = s->next_value; + return s->next_status; + } + + lsp_int16_t c = s->getchar(s); + s->next_available = true; + s->next_value = c; + s->next_status = ((c == LSP_EOF) ? LSP_EOF : LSP_SUCCESS); + + *v = s->next_value; + return s->next_status; +} + + +void lsp_out_stream_init(lsp_out_stream_t *s, lsp_stream_putchar_t putchar) { + s->putchar = putchar; +} + + +lsp_status_t lsp_out_stream_write(lsp_out_stream_t *s, lsp_uint8_t v) { + if (s->putchar(s, v) == LSP_EOF) + return LSP_EOF; + + return LSP_SUCCESS; +} + + +lsp_status_t lsp_out_stream_write_str(lsp_out_stream_t *s, char *str) { + while (*str) { + lsp_status_t status = lsp_out_stream_write(s, *(str++)); + if (status != LSP_SUCCESS) + return status; + } + + return LSP_SUCCESS; +} + + +lsp_status_t lsp_out_stream_write_int(lsp_out_stream_t *s, lsp_int32_t v) { + lsp_status_t status; + if (v < 0) { + v *= -1; + status = lsp_out_stream_write(s, '-'); + if (status != LSP_SUCCESS) + return status; + } + + lsp_uint8_t size = 0; + for (lsp_int32_t i = v; i; i /= 10) + size++; + if (size < 1) + size = 1; + + for (lsp_uint8_t i = 0; i < size; ++i) { + lsp_int32_t temp = v; + for (lsp_uint8_t j = i; j < size - 1; ++j) + temp /= 10; + + lsp_uint8_t digit = temp % 10; + status = lsp_out_stream_write(s, '0' + digit); + if (status != LSP_SUCCESS) + return status; + } + + return LSP_SUCCESS; +} + + +void lsp_str_stream_init(lsp_str_stream_t *s, lsp_mem_t *m, lsp_addr_t str) { + lsp_in_stream_init((lsp_in_stream_t *)s, str_getchar); + s->m = m; + s->str = str; + s->pos = 0; +} diff --git a/src_c/stream.h b/src_c/stream.h new file mode 100644 index 0000000..268f69b --- /dev/null +++ b/src_c/stream.h @@ -0,0 +1,46 @@ +#ifndef LISP16_STREAM_H +#define LISP16_STREAM_H + +#include "mem.h" + + +typedef struct lsp_in_stream_t lsp_in_stream_t; +typedef struct lsp_out_stream_t lsp_out_stream_t; +typedef lsp_int16_t (*lsp_stream_getchar_t)(lsp_in_stream_t *s); +typedef lsp_int16_t (*lsp_stream_putchar_t)(lsp_out_stream_t *s, lsp_int16_t v); + +struct lsp_in_stream_t { + // internal + lsp_stream_getchar_t getchar; + lsp_bool_t next_available; + lsp_uint8_t next_value; + lsp_status_t next_status; +}; + +struct lsp_out_stream_t { + // internal + lsp_stream_putchar_t putchar; +}; + +typedef struct { + lsp_in_stream_t base; + + // internal + lsp_mem_t *m; + lsp_addr_t str; + lsp_uint16_t pos; +} lsp_str_stream_t; + + +void lsp_in_stream_init(lsp_in_stream_t *s, lsp_stream_getchar_t getchar); +lsp_status_t lsp_in_stream_read(lsp_in_stream_t *s, lsp_uint8_t *v); +lsp_status_t lsp_in_stream_peek(lsp_in_stream_t *s, lsp_uint8_t *v); + +void lsp_out_stream_init(lsp_out_stream_t *s, lsp_stream_putchar_t putchar); +lsp_status_t lsp_out_stream_write(lsp_out_stream_t *s, lsp_uint8_t v); +lsp_status_t lsp_out_stream_write_str(lsp_out_stream_t *s, char *str); +lsp_status_t lsp_out_stream_write_int(lsp_out_stream_t *s, lsp_int32_t v); + +void lsp_str_stream_init(lsp_str_stream_t *s, lsp_mem_t *m, lsp_addr_t str); + +#endif diff --git a/src_c/syntax.c b/src_c/syntax.c new file mode 100644 index 0000000..5ec6c7e --- /dev/null +++ b/src_c/syntax.c @@ -0,0 +1,192 @@ +#include "syntax.h" +#include "ctx.h" +#include "eval.h" + + +lsp_builtin_entry_t lsp_syntaxes[] = { + {"lambda", lsp_syntax_lambda}, {"syntax", lsp_syntax_syntax}, + {"define", lsp_syntax_define}, {"set!", lsp_syntax_set}, + {"begin", lsp_syntax_begin}, {"quote", lsp_syntax_quote}, + {"if", lsp_syntax_if}, {NULL, NULL}}; + + +lsp_status_t lsp_syntax_lambda(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + if (args == e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t fn_args = lsp_mem_get_pair_first(e->m, args); + lsp_addr_t fn_body = lsp_mem_get_pair_second(e->m, args); + + if (!lsp_mem_is_symbol(e->m, fn_args) && !lsp_mem_is_pair(e->m, fn_args)) + return LSP_ERR_ARG_TYPE; + + if (fn_body == e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t ctx_copy; + lsp_status_t status = lsp_ctx_copy(e->m, ctx, &ctx_copy); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t result; + status = lsp_mem_create_function(e->m, ctx_copy, fn_args, fn_body, &result); + lsp_mem_dec_ref(e->m, ctx_copy); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_syntax_syntax(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + if (args == e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t syntax_args = lsp_mem_get_pair_first(e->m, args); + lsp_addr_t syntax_body = lsp_mem_get_pair_second(e->m, args); + + if (!lsp_mem_is_symbol(e->m, syntax_args) && + !lsp_mem_is_pair(e->m, syntax_args)) + return LSP_ERR_ARG_TYPE; + + if (syntax_body == e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t ctx_copy; + lsp_status_t status = lsp_ctx_copy(e->m, ctx, &ctx_copy); + if (status != LSP_SUCCESS) + return status; + + lsp_addr_t result; + status = lsp_mem_create_syntax(e->m, ctx_copy, syntax_args, syntax_body, + &result); + lsp_mem_dec_ref(e->m, ctx_copy); + if (status != LSP_SUCCESS) + return status; + + status = lsp_env_set_result_value(e, result); + lsp_mem_dec_ref(e->m, result); + return status; +} + + +lsp_status_t lsp_syntax_define(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t symbol; + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &symbol, &value); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_symbol(e->m, symbol)) + return LSP_ERR_ARG_TYPE; + + status = lsp_env_resolve(e, ctx, value, &value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_ctx_add(e->m, ctx, symbol, value); + lsp_mem_dec_ref(e->m, value); + if (status != LSP_SUCCESS) + return status; + + return lsp_env_set_result_value(e, e->m->nil); +} + + +lsp_status_t lsp_syntax_set(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t symbol; + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_2(e->m, args, &symbol, &value); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_symbol(e->m, symbol)) + return LSP_ERR_ARG_TYPE; + + status = lsp_env_resolve(e, ctx, value, &value); + if (status != LSP_SUCCESS) + return status; + + status = lsp_ctx_set(e->m, ctx, symbol, value); + lsp_mem_dec_ref(e->m, value); + if (status != LSP_SUCCESS) + return status; + + return lsp_env_set_result_value(e, e->m->nil); +} + + +lsp_status_t lsp_syntax_begin(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + if (args == e->m->nil) + return LSP_ERR_ARG_COUNT; + + while (true) { + lsp_addr_t value = lsp_mem_get_pair_first(e->m, args); + lsp_addr_t next_args = lsp_mem_get_pair_second(e->m, args); + + if (next_args == e->m->nil) + return lsp_env_set_result_eval(e, ctx, value); + + lsp_status_t status = lsp_env_resolve(e, ctx, value, &value); + if (status != LSP_SUCCESS) + return status; + + lsp_mem_dec_ref(e->m, value); + args = next_args; + } +} + + +lsp_status_t lsp_syntax_quote(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + lsp_addr_t value; + lsp_status_t status = lsp_builtin_get_args_1(e->m, args, &value); + if (status != LSP_SUCCESS) + return status; + + return lsp_env_set_result_value(e, value); +} + + +lsp_status_t lsp_syntax_if(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args) { + if (args == e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t test = lsp_mem_get_pair_first(e->m, args); + + args = lsp_mem_get_pair_second(e->m, args); + if (args == e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_addr_t true_value = lsp_mem_get_pair_first(e->m, args); + + lsp_addr_t false_value; + args = lsp_mem_get_pair_second(e->m, args); + if (args == e->m->nil) { + false_value = e->m->nil; + + } else { + false_value = lsp_mem_get_pair_first(e->m, args); + args = lsp_mem_get_pair_second(e->m, args); + } + + if (args != e->m->nil) + return LSP_ERR_ARG_COUNT; + + lsp_status_t status = lsp_env_resolve(e, ctx, test, &test); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t is_false = (lsp_mem_is_number(e->m, test) && + lsp_mem_get_number(e->m, test) == 0) || + (lsp_mem_is_pair(e->m, test) && test == e->m->nil) || + (lsp_mem_is_string(e->m, test) && + lsp_mem_get_string_len(e->m, test) == 0) || + (lsp_mem_is_symbol(e->m, test) && + lsp_mem_get_symbol_len(e->m, test) == 0); + lsp_mem_dec_ref(e->m, test); + + return lsp_env_set_result_eval(e, ctx, + (is_false ? false_value : true_value)); +} diff --git a/src_c/syntax.h b/src_c/syntax.h new file mode 100644 index 0000000..55a6516 --- /dev/null +++ b/src_c/syntax.h @@ -0,0 +1,17 @@ +#ifndef LISP16_SYNTAX_H +#define LISP16_SYNTAX_H + +#include "builtin.h" + + +extern lsp_builtin_entry_t lsp_syntaxes[]; + +lsp_status_t lsp_syntax_lambda(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_syntax_syntax(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_syntax_define(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_syntax_set(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_syntax_begin(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_syntax_quote(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); +lsp_status_t lsp_syntax_if(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t args); + +#endif diff --git a/src_c/write.c b/src_c/write.c new file mode 100644 index 0000000..2b18aeb --- /dev/null +++ b/src_c/write.c @@ -0,0 +1,174 @@ +#include "write.h" +#include "function.h" +#include "syntax.h" + + +static lsp_status_t write_number(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + return lsp_out_stream_write_int(s, lsp_mem_get_number(m, addr)); +} + + +static lsp_status_t write_pair(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_status_t status = lsp_out_stream_write(s, '('); + if (status != LSP_SUCCESS) + return status; + + lsp_bool_t write_space = false; + while (addr != m->nil) { + if (write_space) { + lsp_out_stream_write(s, ' '); + } else { + write_space = true; + } + + lsp_addr_t first = lsp_mem_get_pair_first(m, addr); + lsp_addr_t second = lsp_mem_get_pair_second(m, addr); + + status = lsp_write(m, s, first); + if (status != LSP_SUCCESS) + return status; + + if (!lsp_mem_is_pair(m, second)) { + status = lsp_out_stream_write_str(s, " . "); + if (status != LSP_SUCCESS) + return status; + + status = lsp_write(m, s, second); + if (status != LSP_SUCCESS) + return status; + + break; + } + + addr = second; + } + + return lsp_out_stream_write(s, ')'); +} + + +static lsp_status_t write_string(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_uint16_t len = lsp_mem_get_string_len(m, addr); + lsp_status_t status = lsp_out_stream_write(s, '"'); + + for (lsp_uint16_t i = 0; i < len; ++i) { + lsp_uint8_t c = lsp_mem_get_string_data(m, addr, i); + + if (c == '"') { + status = lsp_out_stream_write(s, '\\'); + if (status != LSP_SUCCESS) + return status; + } + + status = lsp_out_stream_write(s, c); + if (status != LSP_SUCCESS) + return status; + } + + return lsp_out_stream_write(s, '"'); +} + + +static lsp_status_t write_symbol(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_uint16_t len = lsp_mem_get_symbol_len(m, addr); + + for (lsp_uint16_t i = 0; i < len; ++i) { + lsp_uint8_t c = lsp_mem_get_symbol_name(m, addr, i); + lsp_status_t status = lsp_out_stream_write(s, c); + if (status != LSP_SUCCESS) + return status; + } + + return LSP_SUCCESS; +} + + +static lsp_status_t write_builtin_function(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_status_t status = lsp_out_stream_write_str(s, "#<builtin-function-"); + if (status != LSP_SUCCESS) + return status; + + status = lsp_out_stream_write_str( + s, lsp_functions[lsp_mem_get_builtin_index(m, addr)].name); + if (status != LSP_SUCCESS) + return status; + + return lsp_out_stream_write(s, '>'); +} + + +static lsp_status_t write_builtin_syntax(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_status_t status = lsp_out_stream_write_str(s, "#<builtin-syntax-"); + if (status != LSP_SUCCESS) + return status; + + status = lsp_out_stream_write_str( + s, lsp_syntaxes[lsp_mem_get_builtin_index(m, addr)].name); + if (status != LSP_SUCCESS) + return status; + + return lsp_out_stream_write(s, '>'); +} + + +static lsp_status_t write_function(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_status_t status = lsp_out_stream_write_str(s, "#<function-"); + if (status != LSP_SUCCESS) + return status; + + status = lsp_out_stream_write_int(s, addr); + if (status != LSP_SUCCESS) + return status; + + return lsp_out_stream_write(s, '>'); +} + + +static lsp_status_t write_syntax(lsp_mem_t *m, lsp_out_stream_t *s, + lsp_addr_t addr) { + lsp_status_t status = lsp_out_stream_write_str(s, "#<syntax-"); + if (status != LSP_SUCCESS) + return status; + + status = lsp_out_stream_write_int(s, addr); + if (status != LSP_SUCCESS) + return status; + + return lsp_out_stream_write(s, '>'); +} + + +lsp_status_t lsp_write(lsp_mem_t *m, lsp_out_stream_t *s, lsp_addr_t addr) { + if (lsp_mem_is_number(m, addr)) + return write_number(m, s, addr); + + if (lsp_mem_is_pair(m, addr)) + return write_pair(m, s, addr); + + if (lsp_mem_is_string(m, addr)) + return write_string(m, s, addr); + + if (lsp_mem_is_symbol(m, addr)) + return write_symbol(m, s, addr); + + if (lsp_mem_is_builtin_function(m, addr)) + return write_builtin_function(m, s, addr); + + if (lsp_mem_is_builtin_syntax(m, addr)) + return write_builtin_syntax(m, s, addr); + + if (lsp_mem_is_function(m, addr)) + return write_function(m, s, addr); + + if (lsp_mem_is_syntax(m, addr)) + return write_syntax(m, s, addr); + + return LSP_ERR_WRITE; +} diff --git a/src_c/write.h b/src_c/write.h new file mode 100644 index 0000000..5b7cff1 --- /dev/null +++ b/src_c/write.h @@ -0,0 +1,10 @@ +#ifndef LISP16_WRITE_H +#define LISP16_WRITE_H + +#include "mem.h" +#include "stream.h" + + +lsp_status_t lsp_write(lsp_mem_t *m, lsp_out_stream_t *s, lsp_addr_t addr); + +#endif |
