added error types and stuff
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
||||
((nil . ((eval . (flycheck-mode 0))
|
||||
((c-mode . ((eval . (flycheck-mode 0))
|
||||
(eval . (rainbow-mode 0)))))
|
||||
|
||||
@@ -8,7 +8,7 @@ typedef enum {
|
||||
Ast_Node_Type_Number,
|
||||
Ast_Node_Type_String,
|
||||
|
||||
Ast_Node_Type_Cons_Cell,
|
||||
Ast_Node_Type_Pair,
|
||||
Ast_Node_Type_Function,
|
||||
Ast_Node_Type_Built_In_Function,
|
||||
} Ast_Node_Type;
|
||||
@@ -32,16 +32,16 @@ typedef struct {
|
||||
typedef struct {
|
||||
struct Ast_Node* first;
|
||||
struct Ast_Node* rest;
|
||||
} Cons_Cell;
|
||||
} Pair;
|
||||
|
||||
typedef struct {
|
||||
Cons_Cell* regular_params;
|
||||
Cons_Cell* keyword_params;
|
||||
Pair* regular_params;
|
||||
Pair* keyword_params;
|
||||
} Lambda_List;
|
||||
|
||||
typedef struct {
|
||||
Lambda_List* parameters;
|
||||
Cons_Cell* form;
|
||||
Pair* form;
|
||||
} Function;
|
||||
|
||||
typedef struct {
|
||||
@@ -51,12 +51,12 @@ typedef struct {
|
||||
struct Ast_Node {
|
||||
Ast_Node_Type type;
|
||||
union {
|
||||
Symbol* symbol;
|
||||
Keyword* keyword;
|
||||
Number* number;
|
||||
String* string;
|
||||
Cons_Cell* cons_cell;
|
||||
Function* function;
|
||||
Symbol* symbol;
|
||||
Keyword* keyword;
|
||||
Number* number;
|
||||
String* string;
|
||||
Pair* pair;
|
||||
Function* function;
|
||||
Built_In_Function* built_in_function;
|
||||
} value;
|
||||
};
|
||||
@@ -67,7 +67,7 @@ typedef struct Ast_Node Ast_Node;
|
||||
Ast_Node* create_ast_node_nil() {
|
||||
Ast_Node* node = new(Ast_Node);
|
||||
node->type = Ast_Node_Type_Nil;
|
||||
node->value.cons_cell = NULL;
|
||||
node->value.pair = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -106,9 +106,9 @@ Ast_Node* create_ast_node_built_in_function(char* identifier) {
|
||||
|
||||
Ast_Node* create_ast_node_pair(Ast_Node* first, Ast_Node* rest) {
|
||||
Ast_Node* node = new(Ast_Node);
|
||||
node->type = Ast_Node_Type_Cons_Cell;
|
||||
node->value.cons_cell = new(Cons_Cell);
|
||||
node->value.cons_cell->first = first;
|
||||
node->value.cons_cell->rest = rest;
|
||||
node->type = Ast_Node_Type_Pair;
|
||||
node->value.pair = new(Pair);
|
||||
node->value.pair->first = first;
|
||||
node->value.pair->rest = rest;
|
||||
return node;
|
||||
}
|
||||
|
||||
+25
-25
@@ -1,52 +1,52 @@
|
||||
Ast_Node* built_in_add(Ast_Node* operands) {
|
||||
double sum = 0;
|
||||
while (operands->type == Ast_Node_Type_Cons_Cell) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
sum += operands->value.cons_cell->first->value.number->value;
|
||||
operands = operands->value.cons_cell->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
sum += operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
|
||||
return create_ast_node_number(sum);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_substract(Ast_Node* operands) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
double difference = operands->value.cons_cell->first->value.number->value;
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
double difference = operands->value.pair->first->value.number->value;
|
||||
|
||||
operands = operands->value.cons_cell->rest;
|
||||
while (operands->type == Ast_Node_Type_Cons_Cell) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
operands = operands->value.pair->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
|
||||
difference -= operands->value.cons_cell->first->value.number->value;
|
||||
operands = operands->value.cons_cell->rest;
|
||||
difference -= operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
return create_ast_node_number(difference);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_multiply(Ast_Node* operands) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
double product = operands->value.cons_cell->first->value.number->value;
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
double product = operands->value.pair->first->value.number->value;
|
||||
|
||||
operands = operands->value.cons_cell->rest;
|
||||
while (operands->type == Ast_Node_Type_Cons_Cell) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
operands = operands->value.pair->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
|
||||
product *= operands->value.cons_cell->first->value.number->value;
|
||||
operands = operands->value.cons_cell->rest;
|
||||
product *= operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
return create_ast_node_number(product);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_divide(Ast_Node* operands) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
double quotient = operands->value.cons_cell->first->value.number->value;
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
double quotient = operands->value.pair->first->value.number->value;
|
||||
|
||||
operands = operands->value.cons_cell->rest;
|
||||
while (operands->type == Ast_Node_Type_Cons_Cell) {
|
||||
assert_type(operands->value.cons_cell->first, Ast_Node_Type_Number);
|
||||
operands = operands->value.pair->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
|
||||
quotient /= operands->value.cons_cell->first->value.number->value;
|
||||
operands = operands->value.cons_cell->rest;
|
||||
quotient /= operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
return create_ast_node_number(quotient);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,43 @@
|
||||
typedef enum {
|
||||
Error_Type_Ill_Formed_List,
|
||||
Error_Type_Wrong_Number_Of_Arguments,
|
||||
Error_Type_Type_Missmatch,
|
||||
Error_Type_Symbol_Not_Defined,
|
||||
Error_Type_Not_A_Function,
|
||||
Error_Type_Not_Yet_Implemented,
|
||||
Error_Type_Unknown_Error,
|
||||
} Error_Type;
|
||||
|
||||
typedef struct {
|
||||
char* message;
|
||||
Ast_Node* location;
|
||||
Error_Type type;
|
||||
Ast_Node* location;
|
||||
} Error;
|
||||
|
||||
Error* error;
|
||||
|
||||
void delete_error() {
|
||||
if (error) {
|
||||
free(error);
|
||||
error = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void create_error(Error_Type type, Ast_Node* location) {
|
||||
delete_error();
|
||||
|
||||
error = new(Error);
|
||||
error->type = type;
|
||||
error->location = location;
|
||||
}
|
||||
|
||||
char* Error_Type_to_string(Error_Type type) {
|
||||
switch (type) {
|
||||
case Error_Type_Ill_Formed_List: return "Ill formed list";
|
||||
case Error_Type_Not_A_Function: return "Not a function";
|
||||
case Error_Type_Symbol_Not_Defined: return "Symbol not defined";
|
||||
case Error_Type_Wrong_Number_Of_Arguments: return "Wrong number of arguments";
|
||||
case Error_Type_Type_Missmatch: return "Type Missmatch";
|
||||
case Error_Type_Not_Yet_Implemented: return "Not yet implemented";
|
||||
case Error_Type_Unknown_Error: return "Unknown Error";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,24 +7,29 @@
|
||||
Ast_Node* eval_expr(Ast_Node* node, Environment* env);
|
||||
int is_truthy (Ast_Node* expression, Environment* env);
|
||||
|
||||
int list_length(Ast_Node* node) {
|
||||
if (node->type != Ast_Node_Type_Pair) {
|
||||
create_error(Error_Type_Type_Missmatch, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void eval_operands(Ast_Node* operands, Environment* env) {
|
||||
while (!error) {
|
||||
if (operands->type == Ast_Node_Type_Cons_Cell) {
|
||||
operands->value.cons_cell->first = eval_expr(operands->value.cons_cell->first, env);
|
||||
operands = operands->value.cons_cell->rest;
|
||||
if (operands->type == Ast_Node_Type_Pair) {
|
||||
operands->value.pair->first = eval_expr(operands->value.pair->first, env);
|
||||
operands = operands->value.pair->rest;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if we reach here we got an error
|
||||
log_error("An error occurred while evaluating operands to a function:");
|
||||
}
|
||||
|
||||
Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
#define report_error(_message) \
|
||||
error = new(Error); \
|
||||
error->message = _message; \
|
||||
error->location = node; \
|
||||
#define report_error(_type) \
|
||||
create_error(_type, node); \
|
||||
return NULL
|
||||
|
||||
Ast_Node* ret = new(Ast_Node);
|
||||
@@ -38,15 +43,15 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
case Ast_Node_Type_String:
|
||||
return node;
|
||||
|
||||
case Ast_Node_Type_Cons_Cell: {
|
||||
Ast_Node* operator = eval_expr(node->value.cons_cell->first, env);
|
||||
Ast_Node* operands = node->value.cons_cell->rest;
|
||||
case Ast_Node_Type_Pair: {
|
||||
Ast_Node* operator = eval_expr(node->value.pair->first, env);
|
||||
Ast_Node* operands = node->value.pair->rest;
|
||||
|
||||
// check for built ins functions
|
||||
if (operator->type == Ast_Node_Type_Built_In_Function) {
|
||||
char* operator_name = operator->value.built_in_function->identifier;
|
||||
if (string_equal("quote", operator_name)) {
|
||||
return node->value.cons_cell->rest;
|
||||
return node->value.pair->rest;
|
||||
} else if (string_equal("+", operator_name)) {
|
||||
eval_operands(operands, env);
|
||||
return built_in_add(operands);
|
||||
@@ -60,25 +65,24 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
eval_operands(operands, env);
|
||||
return built_in_divide(operands);
|
||||
} else if (string_equal("if", operator_name)) {
|
||||
if (Ast_Node_Type_Cons_Cell != operands->value.cons_cell->rest->type ||
|
||||
Ast_Node_Type_Cons_Cell != operands->value.cons_cell->rest->value.cons_cell->rest->type ||
|
||||
Ast_Node_Type_Nil != operands->value.cons_cell->rest->value.cons_cell->rest->value.cons_cell->rest->type)
|
||||
{
|
||||
report_error("Ill formed if statement");
|
||||
if (list_length(operands) != 3) {
|
||||
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||
}
|
||||
|
||||
Ast_Node* then_part = operands->value.cons_cell->rest;
|
||||
Ast_Node* else_part = then_part->value.cons_cell->rest;
|
||||
Ast_Node* condition = operands->value.pair->first;
|
||||
Ast_Node* then_part = operands->value.pair->rest;
|
||||
Ast_Node* else_part = then_part->value.pair->rest;
|
||||
|
||||
if (is_truthy(operands->value.cons_cell->first, env))
|
||||
return eval_expr(then_part->value.cons_cell->first, env);
|
||||
if (is_truthy(condition, env))
|
||||
return eval_expr(then_part->value.pair->first, env);
|
||||
else
|
||||
return eval_expr(else_part->value.cons_cell->first, env);
|
||||
} else if (string_equal("not", operator_name)) {
|
||||
} else if (string_equal("and", operator_name)) {
|
||||
} else if (string_equal("or", operator_name)) {
|
||||
return eval_expr(else_part->value.pair->first, env);
|
||||
/* } else if (string_equal("not", operator_name)) { */
|
||||
|
||||
/* } else if (string_equal("and", operator_name)) { */
|
||||
/* } else if (string_equal("or", operator_name)) { */
|
||||
} else {
|
||||
report_error("The operator is not yet implemented");
|
||||
report_error(Error_Type_Not_Yet_Implemented);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +92,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
}
|
||||
|
||||
default:
|
||||
report_error("Unknown error");
|
||||
report_error(Error_Type_Unknown_Error);
|
||||
}
|
||||
#undef report_error
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#define console_normal "\x1B[0m"
|
||||
#define console_red "\x1B[31m"
|
||||
#define console_green "\x1B[32m"
|
||||
#define console_cyan "\x1B[36m"
|
||||
|
||||
typedef enum {
|
||||
Log_Level_None,
|
||||
|
||||
@@ -24,11 +29,6 @@ void log_message(Log_Level type, char* message) {
|
||||
printf("%s: %s\n",prefix, message);
|
||||
}
|
||||
|
||||
void log_error(char* message) {
|
||||
log_message(Log_Level_Critical, message);
|
||||
log_message(Log_Level_Critical, error->message);
|
||||
}
|
||||
|
||||
|
||||
void panic(char* message) {
|
||||
log_message(Log_Level_Critical, message);
|
||||
@@ -36,24 +36,16 @@ void panic(char* message) {
|
||||
}
|
||||
|
||||
|
||||
char* Ast_Node_Type_to_string (Ast_Node_Type type) {
|
||||
char* Ast_Node_Type_to_string(Ast_Node_Type type) {
|
||||
switch (type) {
|
||||
case(Ast_Node_Type_Nil):
|
||||
return "nil";
|
||||
case(Ast_Node_Type_Number):
|
||||
return "number";
|
||||
case(Ast_Node_Type_String):
|
||||
return "string";
|
||||
case(Ast_Node_Type_Symbol):
|
||||
return "symbol";
|
||||
case(Ast_Node_Type_Keyword):
|
||||
return "keyword";
|
||||
case(Ast_Node_Type_Function):
|
||||
return "function";
|
||||
case(Ast_Node_Type_Built_In_Function):
|
||||
return "built-in function";
|
||||
case(Ast_Node_Type_Cons_Cell):
|
||||
return "pair";
|
||||
case(Ast_Node_Type_Nil): return "nil";
|
||||
case(Ast_Node_Type_Number): return "number";
|
||||
case(Ast_Node_Type_String): return "string";
|
||||
case(Ast_Node_Type_Symbol): return "symbol";
|
||||
case(Ast_Node_Type_Keyword): return "keyword";
|
||||
case(Ast_Node_Type_Function): return "function";
|
||||
case(Ast_Node_Type_Built_In_Function): return "built-in function";
|
||||
case(Ast_Node_Type_Pair): return "pair";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,14 +72,14 @@ void print(Ast_Node* node) {
|
||||
case (Ast_Node_Type_Built_In_Function): {
|
||||
printf("[built-in-function %s]", node->value.built_in_function->identifier);
|
||||
} break;
|
||||
case (Ast_Node_Type_Cons_Cell): {
|
||||
case (Ast_Node_Type_Pair): {
|
||||
Ast_Node* head = node;
|
||||
printf("(");
|
||||
|
||||
while (1) {
|
||||
print(head->value.cons_cell->first);
|
||||
head = head->value.cons_cell->rest;
|
||||
if (head->type != Ast_Node_Type_Cons_Cell)
|
||||
print(head->value.pair->first);
|
||||
head = head->value.pair->rest;
|
||||
if (head->type != Ast_Node_Type_Pair)
|
||||
break;
|
||||
printf(" ");
|
||||
}
|
||||
@@ -101,3 +93,13 @@ void print(Ast_Node* node) {
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void log_error() {
|
||||
printf("\t%s%s%s\n", console_red,
|
||||
Error_Type_to_string(error->type),
|
||||
console_normal);
|
||||
printf("\t in: %s", console_cyan);
|
||||
print(error->location);
|
||||
printf("%s\n", console_normal);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#define console_normal "\x1B[0m"
|
||||
#define console_red "\x1B[31m"
|
||||
#define console_green "\x1B[32m"
|
||||
|
||||
#define epsilon 2.2204460492503131E-16
|
||||
|
||||
#define testresult int
|
||||
@@ -16,16 +12,18 @@
|
||||
__FILE__, __LINE__, (type)value, (type)variable)
|
||||
|
||||
#define print_assert_not_equal_fail(variable, value, type, format) \
|
||||
printf("\n\tAssertion failed for '" #variable "'" \
|
||||
printf("\n\tAssertion failed for '" #variable "'" \
|
||||
"\n\t in %s:%d" \
|
||||
"\n\texpected not: " format \
|
||||
"\n\tgot anyways: " format "\n", \
|
||||
__FILE__, __LINE__, (type)value, (type)variable)
|
||||
|
||||
/* print_assert_not_equal_fail(error, 0, int, "%d"); \ */
|
||||
#define assert_no_error(error) \
|
||||
if (error) { \
|
||||
print_assert_not_equal_fail(error, 0, int, "%d"); \
|
||||
printf("\t%s%s%s\n", console_red, error->message,console_normal); \
|
||||
printf("\n\tExpected no error to occur," \
|
||||
" but an error occured anyways:\n"); \
|
||||
log_error(); \
|
||||
return fail; \
|
||||
} \
|
||||
|
||||
@@ -63,13 +61,12 @@
|
||||
#define invoke_test(name) \
|
||||
printf("" #name ":"); \
|
||||
for(int i = 0; i < 45 - strlen(#name); ++i) \
|
||||
printf(" "); \
|
||||
printf(" "); \
|
||||
if (name() == pass) \
|
||||
printf("%spassed%s\n", console_green, console_normal); \
|
||||
else { \
|
||||
printf("%sfailed%s\n", console_red, console_normal); \
|
||||
if(error) { \
|
||||
log_error("Error while running test" #name); \
|
||||
free(error); \
|
||||
error = NULL; \
|
||||
} \
|
||||
|
||||
@@ -14,9 +14,18 @@
|
||||
|
||||
** DONE if
|
||||
CLOSED: [2018-09-18 Di 12:14]
|
||||
** TODO and
|
||||
** TODO and (short circuiting)
|
||||
** TODO or
|
||||
** TODO not
|
||||
#+begin_src emacs-lisp
|
||||
(not 1) ;; == (not . (1 . nil))
|
||||
(not (expression 1 3)) ;; == (not . ((expression . (1 . (3 . nil))) . nil))
|
||||
(not) ;; == (not . nil)
|
||||
(not 1 2) ;; == (not . (1 . (2 . nil)))
|
||||
#+end_src
|
||||
|
||||
#+RESULTS:
|
||||
: t
|
||||
|
||||
** TODO first (car)
|
||||
** TODO rest (cdr)
|
||||
|
||||
Reference in New Issue
Block a user