Fix some bugs with the reader
This commit is contained in:
13
src/lisp.c
13
src/lisp.c
@ -887,6 +887,7 @@ DEF_STATIC_SYMBOL(finally, ":finally");
|
|||||||
DEF_STATIC_SYMBOL(shutdown_signal, "shutdown-signal");
|
DEF_STATIC_SYMBOL(shutdown_signal, "shutdown-signal");
|
||||||
DEF_STATIC_SYMBOL(type_error, "type-error");
|
DEF_STATIC_SYMBOL(type_error, "type-error");
|
||||||
DEF_STATIC_SYMBOL(read_error, "read-error");
|
DEF_STATIC_SYMBOL(read_error, "read-error");
|
||||||
|
DEF_STATIC_SYMBOL(unclosed_error, "read-error");
|
||||||
DEF_STATIC_SYMBOL(eof_error, "eof-error");
|
DEF_STATIC_SYMBOL(eof_error, "eof-error");
|
||||||
DEF_STATIC_SYMBOL(void_variable_error, "void-variable-error");
|
DEF_STATIC_SYMBOL(void_variable_error, "void-variable-error");
|
||||||
DEF_STATIC_SYMBOL(void_function_error, "void-function-error");
|
DEF_STATIC_SYMBOL(void_function_error, "void-function-error");
|
||||||
@ -1052,6 +1053,7 @@ void lisp_init(void) {
|
|||||||
REGISTER_SYMBOL(type_error);
|
REGISTER_SYMBOL(type_error);
|
||||||
REGISTER_SYMBOL(read_error);
|
REGISTER_SYMBOL(read_error);
|
||||||
REGISTER_SYMBOL(eof_error);
|
REGISTER_SYMBOL(eof_error);
|
||||||
|
REGISTER_SYMBOL(unclosed_error);
|
||||||
REGISTER_SYMBOL(void_variable_error);
|
REGISTER_SYMBOL(void_variable_error);
|
||||||
REGISTER_SYMBOL(void_function_error);
|
REGISTER_SYMBOL(void_function_error);
|
||||||
REGISTER_SYMBOL(circular_error);
|
REGISTER_SYMBOL(circular_error);
|
||||||
@ -1623,9 +1625,20 @@ DEFUN(eval_in_env, "eval-in-env", (LispVal * form, LispVal *lexenv)) {
|
|||||||
case TYPE_VECTOR: {
|
case TYPE_VECTOR: {
|
||||||
LispVector *vec = (LispVector *) form;
|
LispVector *vec = (LispVector *) form;
|
||||||
LispVal **elts = lisp_malloc(sizeof(LispVal *) * vec->length);
|
LispVal **elts = lisp_malloc(sizeof(LispVal *) * vec->length);
|
||||||
|
if (elts) { // in case length is 0
|
||||||
|
memset(elts, 0, sizeof(LispVal *) * vec->length);
|
||||||
|
}
|
||||||
|
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||||
|
struct UnrefListData uld;
|
||||||
|
uld.vals = elts;
|
||||||
|
uld.len = vec->length;
|
||||||
|
void *cl_handler =
|
||||||
|
register_cleanup(&unref_free_list_double_ptr, &uld);
|
||||||
for (size_t i = 0; i < vec->length; ++i) {
|
for (size_t i = 0; i < vec->length; ++i) {
|
||||||
elts[i] = Feval_in_env(vec->data[i], lexenv);
|
elts[i] = Feval_in_env(vec->data[i], lexenv);
|
||||||
}
|
}
|
||||||
|
cancel_cleanup(cl_handler);
|
||||||
|
});
|
||||||
// does not ref its arguments
|
// does not ref its arguments
|
||||||
return make_lisp_vector(elts, vec->length);
|
return make_lisp_vector(elts, vec->length);
|
||||||
}
|
}
|
||||||
|
@ -491,6 +491,13 @@ void cancel_cleanup(void *handle);
|
|||||||
cancel_cleanup(__with_cleanup_cleanup); \
|
cancel_cleanup(__with_cleanup_cleanup); \
|
||||||
refcount_unref(var); \
|
refcount_unref(var); \
|
||||||
}
|
}
|
||||||
|
#define WITH_CLEANUP_IF_THROW(var, body) \
|
||||||
|
{ \
|
||||||
|
void *__with_cleanup_cleanup = \
|
||||||
|
register_cleanup(&refcount_unref_as_callback, (var)); \
|
||||||
|
{body}; \
|
||||||
|
cancel_cleanup(__with_cleanup_cleanup); \
|
||||||
|
}
|
||||||
|
|
||||||
DECLARE_FUNCTION(backtrace, (void) );
|
DECLARE_FUNCTION(backtrace, (void) );
|
||||||
noreturn DECLARE_FUNCTION(return_from, (LispVal * name, LispVal *value));
|
noreturn DECLARE_FUNCTION(return_from, (LispVal * name, LispVal *value));
|
||||||
@ -502,6 +509,7 @@ extern LispVal *Qshutdown_signal;
|
|||||||
extern LispVal *Qtype_error;
|
extern LispVal *Qtype_error;
|
||||||
extern LispVal *Qread_error;
|
extern LispVal *Qread_error;
|
||||||
extern LispVal *Qeof_error;
|
extern LispVal *Qeof_error;
|
||||||
|
extern LispVal *Qunclosed_error;
|
||||||
extern LispVal *Qvoid_variable_error;
|
extern LispVal *Qvoid_variable_error;
|
||||||
extern LispVal *Qvoid_function_error;
|
extern LispVal *Qvoid_function_error;
|
||||||
extern LispVal *Qcircular_error;
|
extern LispVal *Qcircular_error;
|
||||||
|
46
src/read.c
46
src/read.c
@ -50,12 +50,13 @@ static inline _Noreturn void _internal_read_error(struct ReadState *state,
|
|||||||
LispVal *col = make_lisp_integer(state->col);
|
LispVal *col = make_lisp_integer(state->col);
|
||||||
LispVal *ctx = make_lisp_string(state->head, len, false, false);
|
LispVal *ctx = make_lisp_string(state->head, len, false, false);
|
||||||
LispVal *args = const_list(false, 4, line, col, ctx, refcount_ref(desc));
|
LispVal *args = const_list(false, 4, line, col, ctx, refcount_ref(desc));
|
||||||
WITH_CLEANUP(args, {
|
Fthrow(cause, args);
|
||||||
Fthrow(cause, args); //
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
#define READ_ERROR(state, len, ...) \
|
#define READ_ERROR(state, len, ...) \
|
||||||
_internal_read_error(state, len, sprintf_lisp(__VA_ARGS__), Qread_error)
|
_internal_read_error(state, len, sprintf_lisp(__VA_ARGS__), Qread_error)
|
||||||
|
#define UNCLOSED_ERROR(state, type) \
|
||||||
|
_internal_read_error(state, 1, sprintf_lisp("unterminated %s", type), \
|
||||||
|
Qunclosed_error)
|
||||||
#define EOF_ERROR(state) \
|
#define EOF_ERROR(state) \
|
||||||
_internal_read_error(state, 1, sprintf_lisp("unexpected end of file"), \
|
_internal_read_error(state, 1, sprintf_lisp("unexpected end of file"), \
|
||||||
Qeof_error)
|
Qeof_error)
|
||||||
@ -65,6 +66,11 @@ static inline _Noreturn void _internal_read_error(struct ReadState *state,
|
|||||||
popc(state); \
|
popc(state); \
|
||||||
}
|
}
|
||||||
#define SKIP_WHITESPACE(state) SKIP_WHILE(isspace(peekc(state)), state)
|
#define SKIP_WHITESPACE(state) SKIP_WHILE(isspace(peekc(state)), state)
|
||||||
|
#define SKIP_COMMENT(state) \
|
||||||
|
for (int c = peekc(state); c == ';'; c = peekc(state)) { \
|
||||||
|
SKIP_WHILE(peekc(state) != '\n', state); \
|
||||||
|
SKIP_WHITESPACE(state); \
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_symbol_end(int c) {
|
static bool is_symbol_end(int c) {
|
||||||
return c == EOS || isspace(c) || c == '(' || c == ')' || c == '['
|
return c == EOS || isspace(c) || c == '(' || c == ')' || c == '['
|
||||||
@ -86,11 +92,12 @@ static LispVal *read_list(struct ReadState *state) {
|
|||||||
LispVal *list = Qnil;
|
LispVal *list = Qnil;
|
||||||
LispVal *end = list;
|
LispVal *end = list;
|
||||||
SKIP_WHITESPACE(state);
|
SKIP_WHITESPACE(state);
|
||||||
|
SKIP_COMMENT(state);
|
||||||
int c;
|
int c;
|
||||||
while ((c = peekc(state)) != ')') {
|
while ((c = peekc(state)) != ')') {
|
||||||
if (c == EOS) {
|
if (c == EOS) {
|
||||||
refcount_unref(list);
|
refcount_unref(list);
|
||||||
EOF_ERROR(state);
|
UNCLOSED_ERROR(state, "list");
|
||||||
}
|
}
|
||||||
LispVal *elt = read_internal(state);
|
LispVal *elt = read_internal(state);
|
||||||
if (is_dot_symbol(elt)) {
|
if (is_dot_symbol(elt)) {
|
||||||
@ -101,12 +108,13 @@ static LispVal *read_list(struct ReadState *state) {
|
|||||||
SKIP_WHITESPACE(state);
|
SKIP_WHITESPACE(state);
|
||||||
if (c == EOS) {
|
if (c == EOS) {
|
||||||
refcount_unref(list);
|
refcount_unref(list);
|
||||||
EOF_ERROR(state);
|
UNCLOSED_ERROR(state, "list");
|
||||||
}
|
}
|
||||||
LispVal *last = read_internal(state);
|
LispVal *last = read_internal(state);
|
||||||
Fsettail(end, last);
|
Fsettail(end, last);
|
||||||
refcount_unref(last);
|
refcount_unref(last);
|
||||||
SKIP_WHITESPACE(state);
|
SKIP_WHITESPACE(state);
|
||||||
|
SKIP_COMMENT(state);
|
||||||
if (peekc(state) != ')') {
|
if (peekc(state) != ')') {
|
||||||
refcount_unref(list);
|
refcount_unref(list);
|
||||||
READ_ERROR(state, 1,
|
READ_ERROR(state, 1,
|
||||||
@ -125,6 +133,7 @@ static LispVal *read_list(struct ReadState *state) {
|
|||||||
end = new_end;
|
end = new_end;
|
||||||
}
|
}
|
||||||
SKIP_WHITESPACE(state);
|
SKIP_WHITESPACE(state);
|
||||||
|
SKIP_COMMENT(state);
|
||||||
}
|
}
|
||||||
popc(state); // close )
|
popc(state); // close )
|
||||||
return list;
|
return list;
|
||||||
@ -135,10 +144,11 @@ static LispVal *read_vector(struct ReadState *state) {
|
|||||||
LispVal **values = NULL;
|
LispVal **values = NULL;
|
||||||
size_t values_len = 0;
|
size_t values_len = 0;
|
||||||
SKIP_WHITESPACE(state);
|
SKIP_WHITESPACE(state);
|
||||||
|
SKIP_COMMENT(state);
|
||||||
int c;
|
int c;
|
||||||
while ((c = peekc(state)) != ']') {
|
while ((c = peekc(state)) != ']') {
|
||||||
if (c == EOS) {
|
if (c == EOS) {
|
||||||
EOF_ERROR(state);
|
UNCLOSED_ERROR(state, "vector");
|
||||||
for (size_t i = 0; i < values_len; ++i) {
|
for (size_t i = 0; i < values_len; ++i) {
|
||||||
refcount_unref(values[i]);
|
refcount_unref(values[i]);
|
||||||
}
|
}
|
||||||
@ -149,6 +159,7 @@ static LispVal *read_vector(struct ReadState *state) {
|
|||||||
values = lisp_realloc(values, sizeof(LispVal *) * ++values_len);
|
values = lisp_realloc(values, sizeof(LispVal *) * ++values_len);
|
||||||
values[values_len - 1] = elt;
|
values[values_len - 1] = elt;
|
||||||
SKIP_WHITESPACE(state);
|
SKIP_WHITESPACE(state);
|
||||||
|
SKIP_COMMENT(state);
|
||||||
}
|
}
|
||||||
popc(state); // close ]
|
popc(state); // close ]
|
||||||
return make_lisp_vector(values, values_len);
|
return make_lisp_vector(values, values_len);
|
||||||
@ -165,7 +176,7 @@ static LispVal *read_string(struct ReadState *state) {
|
|||||||
c = popc(state);
|
c = popc(state);
|
||||||
if (c == EOS) {
|
if (c == EOS) {
|
||||||
lisp_free(str);
|
lisp_free(str);
|
||||||
EOF_ERROR(state);
|
UNCLOSED_ERROR(state, "string");
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
if (!backslash && c == '\\') {
|
if (!backslash && c == '\\') {
|
||||||
@ -288,9 +299,6 @@ static LispVal *read_symbol(struct ReadState *state) {
|
|||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
free(str);
|
free(str);
|
||||||
READ_ERROR(state, 1, "backslash not escaping anything");
|
READ_ERROR(state, 1, "backslash not escaping anything");
|
||||||
} else if (c == EOS) {
|
|
||||||
free(str);
|
|
||||||
EOF_ERROR(state);
|
|
||||||
} else {
|
} else {
|
||||||
str = lisp_realloc(str, ++str_len + 1);
|
str = lisp_realloc(str, ++str_len + 1);
|
||||||
str[str_len - 1] = c;
|
str[str_len - 1] = c;
|
||||||
@ -374,13 +382,8 @@ change_to_symbol:
|
|||||||
|
|
||||||
static LispVal *read_internal(struct ReadState *state) {
|
static LispVal *read_internal(struct ReadState *state) {
|
||||||
SKIP_WHILE(isspace(peekc(state)), state);
|
SKIP_WHILE(isspace(peekc(state)), state);
|
||||||
|
SKIP_COMMENT(state);
|
||||||
int c = peekc(state);
|
int c = peekc(state);
|
||||||
// comment
|
|
||||||
while (c == ';') {
|
|
||||||
SKIP_WHILE(peekc(state) != '\n', state);
|
|
||||||
SKIP_WHITESPACE(state);
|
|
||||||
c = peekc(state);
|
|
||||||
}
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
// list
|
// list
|
||||||
case EOS:
|
case EOS:
|
||||||
@ -472,7 +475,10 @@ size_t read_from_buffer(const char *text, size_t length, LispVal **out) {
|
|||||||
.col = 0,
|
.col = 0,
|
||||||
.backquote_level = 0,
|
.backquote_level = 0,
|
||||||
};
|
};
|
||||||
LispVal *res = read_internal(&state);
|
LispVal *res = NULL;
|
||||||
|
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||||
|
res = read_internal(&state); //
|
||||||
|
});
|
||||||
if (!res) {
|
if (!res) {
|
||||||
*out = Qnil;
|
*out = Qnil;
|
||||||
return LISP_EOF;
|
return LISP_EOF;
|
||||||
@ -484,6 +490,7 @@ size_t read_from_buffer(const char *text, size_t length, LispVal **out) {
|
|||||||
|
|
||||||
DEFUN(read, "read", (LispVal * source)) {
|
DEFUN(read, "read", (LispVal * source)) {
|
||||||
LispString *str = (LispString *) source;
|
LispString *str = (LispString *) source;
|
||||||
|
CHECK_TYPE(TYPE_STRING, source);
|
||||||
struct ReadState state = {
|
struct ReadState state = {
|
||||||
.head = str->data,
|
.head = str->data,
|
||||||
.left = str->length,
|
.left = str->length,
|
||||||
@ -492,7 +499,10 @@ DEFUN(read, "read", (LispVal * source)) {
|
|||||||
.col = 0,
|
.col = 0,
|
||||||
.backquote_level = 0,
|
.backquote_level = 0,
|
||||||
};
|
};
|
||||||
LispVal *res = read_internal(&state);
|
LispVal *res = NULL;
|
||||||
|
WITH_PUSH_FRAME(Qnil, Qnil, true, {
|
||||||
|
res = read_internal(&state); //
|
||||||
|
});
|
||||||
if (!res) {
|
if (!res) {
|
||||||
EOF_ERROR(&state);
|
EOF_ERROR(&state);
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user