Improve parser errors slightly
This commit is contained in:
@@ -79,7 +79,12 @@ int main(int argc, const char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_object *sexp = ucl_parse(line);
|
struct ucl_object *sexp = ucl_parse(line);
|
||||||
struct ucl_object *result = ucl_evaluate(scope, ucl_car(sexp));
|
struct ucl_object *result = NULL;
|
||||||
|
if (sexp->type == UCL_TYPE_ERROR) {
|
||||||
|
result = sexp;
|
||||||
|
} else {
|
||||||
|
result = ucl_evaluate(scope, ucl_car(sexp));
|
||||||
|
}
|
||||||
ucl_print_obj(result);
|
ucl_print_obj(result);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
|||||||
38
src/parse.c
38
src/parse.c
@@ -1,5 +1,6 @@
|
|||||||
#include "uclisp.h"
|
#include "uclisp.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
// TODO: remove these
|
// TODO: remove these
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -20,6 +21,8 @@ static const char *reserved_symbols[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remove malloc and strndup calls
|
// TODO: remove malloc and strndup calls
|
||||||
|
// TODO: refresh this with newer 'object' code
|
||||||
|
// TODO: Syntatic sugar for quote
|
||||||
|
|
||||||
static bool ucl_is_whitespace(char c) {
|
static bool ucl_is_whitespace(char c) {
|
||||||
return c == ' ' || c == '\n' || c == '\t';
|
return c == ' ' || c == '\n' || c == '\t';
|
||||||
@@ -68,6 +71,7 @@ struct ucl_object *ucl_token_next(const char **curr_src) {
|
|||||||
str = strndup(start + 1, *curr_src - start - 2);
|
str = strndup(start + 1, *curr_src - start - 2);
|
||||||
return ucl_cell_create(ucl_string_create(str), NULL);
|
return ucl_cell_create(ucl_string_create(str), NULL);
|
||||||
case '0'...'9': {
|
case '0'...'9': {
|
||||||
|
// TODO: Add support for negative integers
|
||||||
char *end = NULL;
|
char *end = NULL;
|
||||||
long value = strtol(*curr_src, &end, 0);
|
long value = strtol(*curr_src, &end, 0);
|
||||||
*curr_src = end;
|
*curr_src = end;
|
||||||
@@ -141,6 +145,9 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
|||||||
assert((*token_iter)->type == UCL_TYPE_CELL);
|
assert((*token_iter)->type == UCL_TYPE_CELL);
|
||||||
|
|
||||||
struct ucl_object *token = (*token_iter)->cell.car;
|
struct ucl_object *token = (*token_iter)->cell.car;
|
||||||
|
if (token == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
struct ucl_object *next_sexp = ucl_parse_token_atom(token);
|
struct ucl_object *next_sexp = ucl_parse_token_atom(token);
|
||||||
if (next_sexp != NULL) {
|
if (next_sexp != NULL) {
|
||||||
*token_iter = (*token_iter)->cell.cdr;
|
*token_iter = (*token_iter)->cell.cdr;
|
||||||
@@ -154,7 +161,13 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
|||||||
// Consume the START_LIST_CHAR
|
// Consume the START_LIST_CHAR
|
||||||
*token_iter = (*token_iter)->cell.cdr;
|
*token_iter = (*token_iter)->cell.cdr;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (*token_iter == NULL) {
|
||||||
|
// Unexpected end of parsing
|
||||||
|
return ucl_error_create("Unmatched open parenthesis");
|
||||||
|
}
|
||||||
|
|
||||||
token = (*token_iter)->cell.car;
|
token = (*token_iter)->cell.car;
|
||||||
|
|
||||||
if (token->type == UCL_TYPE_SYMBOL && token->symbol[0] == END_LIST_CHAR) {
|
if (token->type == UCL_TYPE_SYMBOL && token->symbol[0] == END_LIST_CHAR) {
|
||||||
*token_iter = (*token_iter)->cell.cdr;
|
*token_iter = (*token_iter)->cell.cdr;
|
||||||
if (list == NULL) {
|
if (list == NULL) {
|
||||||
@@ -164,6 +177,7 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
|||||||
}
|
}
|
||||||
|
|
||||||
next_sexp = ucl_parse_tokens_recursive(token_iter);
|
next_sexp = ucl_parse_tokens_recursive(token_iter);
|
||||||
|
UCL_RET_IF_ERROR(next_sexp);
|
||||||
if (next_sexp == NULL) {
|
if (next_sexp == NULL) {
|
||||||
// Error somewhere in the recursive parsing
|
// Error somewhere in the recursive parsing
|
||||||
ucl_object_delete(list);
|
ucl_object_delete(list);
|
||||||
@@ -174,12 +188,11 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i
|
|||||||
next_node = &(*next_node)->cell.cdr;
|
next_node = &(*next_node)->cell.cdr;
|
||||||
}
|
}
|
||||||
} else if (token->symbol[0] == END_LIST_CHAR) {
|
} else if (token->symbol[0] == END_LIST_CHAR) {
|
||||||
// Mismatched parens
|
return ucl_error_create("Unmatched closed parenthesis");
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
// Any other symbol type should have been an atom, this shouldn't happen
|
// Any other symbol type should have been an atom, this shouldn't happen
|
||||||
assert(false);
|
assert(false);
|
||||||
return NULL;
|
return ucl_error_create("Unreachable parse error");
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse_tokens -> doesn't care about quotes, terminates on EOF
|
// parse_tokens -> doesn't care about quotes, terminates on EOF
|
||||||
@@ -192,8 +205,8 @@ struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) {
|
|||||||
|
|
||||||
while (*token_iter != NULL) {
|
while (*token_iter != NULL) {
|
||||||
struct ucl_object *new_sexp = ucl_parse_tokens_recursive(token_iter);
|
struct ucl_object *new_sexp = ucl_parse_tokens_recursive(token_iter);
|
||||||
if (new_sexp == NULL) {
|
if (new_sexp == NULL || new_sexp->type == UCL_TYPE_ERROR) {
|
||||||
goto error;
|
return new_sexp;
|
||||||
}
|
}
|
||||||
|
|
||||||
*next_cell = ucl_cell_create(new_sexp, NULL);
|
*next_cell = ucl_cell_create(new_sexp, NULL);
|
||||||
@@ -206,7 +219,6 @@ struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) {
|
|||||||
|
|
||||||
return resultl;
|
return resultl;
|
||||||
error:
|
error:
|
||||||
ucl_object_delete(resultl);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,13 +226,13 @@ struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) {
|
|||||||
// all sexps in the source (return a list of sexps)?
|
// all sexps in the source (return a list of sexps)?
|
||||||
struct ucl_object *ucl_parse(const char *source) {
|
struct ucl_object *ucl_parse(const char *source) {
|
||||||
struct ucl_object *tokens = ucl_tokenize(source);
|
struct ucl_object *tokens = ucl_tokenize(source);
|
||||||
|
if (tokens == NULL) {
|
||||||
|
tokens = ucl_nil_create();
|
||||||
|
}
|
||||||
|
UCL_RET_IF_ERROR(tokens);
|
||||||
struct ucl_object *sexp = ucl_parse_tokens(tokens);
|
struct ucl_object *sexp = ucl_parse_tokens(tokens);
|
||||||
ucl_object_delete(tokens);
|
if (sexp == NULL) {
|
||||||
|
return ucl_nil_create();
|
||||||
|
}
|
||||||
return sexp;
|
return sexp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* struct ParseResult *ucl_parse(const char *source) { */
|
|
||||||
/* struct Cell *tokens = ucl_tokenize(source); */
|
|
||||||
/* struct Cell *sexp = n */
|
|
||||||
|
|
||||||
/* } */
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
// TODO: Macro support?
|
||||||
|
|
||||||
struct ucl_object *ucl_special_let(struct ucl_scope *scope, struct ucl_object *args) {
|
struct ucl_object *ucl_special_let(struct ucl_scope *scope, struct ucl_object *args) {
|
||||||
// TODO: Check arguments
|
// TODO: Check arguments
|
||||||
struct ucl_object *assignments = ucl_car(args);
|
struct ucl_object *assignments = ucl_car(args);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "uclisp.h"
|
#include "uclisp.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "testing_helpers.h"
|
||||||
|
|
||||||
/* static struct ucl_parse_result *result; */
|
/* static struct ucl_parse_result *result; */
|
||||||
static struct ucl_object *response;
|
static struct ucl_object *response;
|
||||||
@@ -331,6 +332,20 @@ static void test_parse_nested(void) {
|
|||||||
TEST_ASSERT_EQUAL_STRING("foo", response->cell.car->cell.car->cell.car->symbol);
|
TEST_ASSERT_EQUAL_STRING("foo", response->cell.car->cell.car->cell.car->symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_parse_mismatched_open(void) {
|
||||||
|
response = ucl_parse("(");
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_NULL(response);
|
||||||
|
TEST_ASSERT_OBJ_ERROR(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_parse_mismatched_closed(void) {
|
||||||
|
response = ucl_parse(")");
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_NULL(response);
|
||||||
|
TEST_ASSERT_OBJ_ERROR(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
@@ -357,5 +372,7 @@ int main(void) {
|
|||||||
RUN_TEST(test_parse_2elem);
|
RUN_TEST(test_parse_2elem);
|
||||||
RUN_TEST(test_parse_2elem_str);
|
RUN_TEST(test_parse_2elem_str);
|
||||||
RUN_TEST(test_parse_nested);
|
RUN_TEST(test_parse_nested);
|
||||||
|
RUN_TEST(test_parse_mismatched_open);
|
||||||
|
RUN_TEST(test_parse_mismatched_closed);
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user