Builtin functions#
In following examples, lines starting with >
represent characters
provided to input stream. Lines without starting >
character represent
evaluation results written to output stream.
Available builtin functions:
eval
apply
error
cons
set-car!
set-cdr!
number?
pair?
string?
symbol?
function?
syntax?
eq?
equal?
>
<
+
-
*
/
read
read-u8
peek-u8
write
write-u8
make-string
string-length
string-ref
string-set!
Source code#
function.h#
#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
function.c#
#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);
}