We have the beginning of a stdlib and can parse keyword and rest args

This commit is contained in:
FelixBrendel
2018-10-20 23:27:51 +02:00
parent 42d64a0743
commit 488b47f08f
10 changed files with 306 additions and 21 deletions
+7 -11
View File
@@ -1,4 +1,5 @@
struct Ast_Node;
define_array_list(struct Ast_Node*, Ast_Node);
typedef enum {
Ast_Node_Type_Nil,
@@ -36,13 +37,8 @@ typedef struct {
} Pair;
typedef struct {
struct Ast_Node** data;
int length;
int next_index;
} Ast_Node_Array_List;
typedef struct {
// TODO(Felix) use Ast_Node_symbols here instead, so we don't have
// to convert them to strings and back to symbols
char** identifiers;
int next_index;
int length;
@@ -58,8 +54,8 @@ typedef struct {
} Keyword_Arguments;
Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length);
void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, struct Ast_Node* node);
/* Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length); */
/* void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, struct Ast_Node* node); */
Positional_Arguments* create_positional_argument_list(int initial_capacity) {
Positional_Arguments* ret = new(Positional_Arguments);
@@ -80,7 +76,7 @@ void append_to_positional_argument_list(Positional_Arguments* args, char* identi
Keyword_Arguments* create_keyword_argument_list(int initial_capacity) {
Keyword_Arguments* ret = new(Keyword_Arguments);
ret->identifiers = (char**)malloc(initial_capacity * sizeof(char*));
ret->values = create_Ast_Node_Array_List(initial_capacity);
ret->values = create_Ast_Node_array_list(initial_capacity);
ret->next_index = 0;
ret->length = initial_capacity;
return ret;
@@ -96,7 +92,7 @@ void append_to_keyword_argument_list(Keyword_Arguments* args,
}
args->identifiers[args->next_index++] = identifier;
append_to_Ast_Node_Array_List(args->values, default_value);
append_to_Ast_Node_array_list(args->values, default_value);
}
+23
View File
@@ -1,3 +1,5 @@
Ast_Node* eval_expr(Ast_Node* node, Environment* env);
bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) {
if (n1 == n2)
return true;
@@ -120,3 +122,24 @@ Ast_Node* built_in_divide(Ast_Node* operands) {
}
return create_ast_node_number(quotient);
}
Ast_Node* built_in_load(char* file_name, Environment* env) {
char* file_content = read_entire_file(file_name);
if (file_content) {
Ast_Node* result = create_ast_node_nil();
Ast_Node_Array_List* program;
try {
program = parse_program(file_content);
}
for (int i = 0; i < program->next_index; ++i) {
try {
result = eval_expr(program->data[i], env);
}
}
return result;
} else {
create_error(Error_Type_Unknown_Error, create_ast_node_nil());
return nullptr;
}
}
+1
View File
@@ -60,5 +60,6 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) {
return built_in;
create_error(Error_Type_Symbol_Not_Defined, create_ast_node_nil());
printf("%s\n", sym->identifier);
return nullptr;
}
+156 -5
View File
@@ -6,6 +6,9 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E
// positional arguments
for (int i = 0; i < function->positional_arguments->next_index; ++i) {
if (arguments->type == Ast_Node_Type_Pair) {
// TODO(Felix): here we create new ast_node_symbols from
// their identifiers but before we converted them to
// strings from symbols... Wo maybe just use the symbols?
define_symbol(
create_ast_node_symbol(function->positional_arguments->identifiers[i]),
arguments->value.pair->first, new_env);
@@ -17,6 +20,122 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E
arguments = arguments->value.pair->rest;
}
if (arguments->type == Ast_Node_Type_Nil)
goto eval_time;
String_Array_List* read_in_keywords = create_String_array_list(16);
// keyword arguments: use all given ones and keep track of the
// added ones (array list), if end of parameters in encountered or
// something that is not a keyword is encountered or a keyword
// that is not recognized is encoutered, jump out of the loop.
while (arguments->value.pair->first->type == Ast_Node_Type_Keyword) {
// check if this one is even an accepted keyword
bool accepted = false;
for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
if (string_equal(
arguments->value.pair->first->value.keyword->identifier,
function->keyword_arguments->identifiers[i]))
{
accepted = true;
break;
}
}
if (!accepted) {
create_error(Error_Type_Ill_Formed_Arguments, arguments);
return nullptr;
}
// check if it was already read in
for (int i = 0; i < read_in_keywords->next_index; ++i) {
if (string_equal(
arguments->value.pair->first->value.keyword->identifier,
read_in_keywords->data[i]))
{
// TODO(Felix): if we are actually done with all the
// necessary keywords then we have to count the rest
// as :rest here, instead od always creating an error
// (special case with default variables)
create_error(Error_Type_Ill_Formed_Arguments, arguments);
return nullptr;
}
}
// okay so we found a keyword that has to be read in and was
// not already read in, is there a next element to actually
// set it to?
if (arguments->value.pair->rest->type != Ast_Node_Type_Pair) {
create_error(Error_Type_Ill_Formed_Arguments, arguments);
return nullptr;
}
// if not set it and then add it to the array list
define_symbol(
create_ast_node_symbol(arguments->value.pair->first->value.keyword->identifier),
arguments->value.pair->rest->value.pair->first, new_env);
append_to_String_array_list(read_in_keywords, arguments->value.pair->first->value.keyword->identifier);
// overstep both for next one
arguments = arguments->value.pair->rest->value.pair->rest;
if (arguments->type == Ast_Node_Type_Nil) {
break;
}
}
// check if all necessary keywords have been read in
for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
char* defined_keyword = function->keyword_arguments->identifiers[i];
bool was_set = false;
for (int j = 0; j < read_in_keywords->next_index; ++j) {
if (string_equal(
read_in_keywords->data[j],
defined_keyword))
{
was_set = true;
break;
}
}
if (function->keyword_arguments->values->data[i] == nullptr) {
// if this one does not have a default value
if (!was_set) {
create_error(Error_Type_Ill_Formed_Arguments, arguments);
return nullptr;
}
} else {
// this one does have a default value, lets see if we have
// to use it or if the user supplied his own
if (!was_set) {
define_symbol(
create_ast_node_symbol(defined_keyword),
function->keyword_arguments->values->data[i], new_env);
}
}
}
if (arguments->type == Ast_Node_Type_Nil) {
if (function->rest_argument) {
define_symbol(
create_ast_node_symbol(function->rest_argument),
create_ast_node_nil(), new_env);
}
} else {
if (function->rest_argument) {
define_symbol(
create_ast_node_symbol(function->rest_argument),
arguments, new_env);
} else {
// rest was not declared but additional arguments were found
create_error(Error_Type_Ill_Formed_Arguments, arguments);
return nullptr;
}
}
eval_time:
Ast_Node* result;
try {
@@ -26,7 +145,16 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E
return result;
}
/* (define type (lambda (e) (if (and (= (old-type e) :pair) (= (first e) :my-type)) :my-type (old-type e)))) */
/*
(prog
(define type--before type)
(define type
(lambda (e)
(if (and (= (type--before e) :pair) (= (first e) :my-type))
:my-type
(type--before e))))
)
*/
/**
This parses the argument specification of funcitons into their
@@ -281,7 +409,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
return node;
case Ast_Node_Type_Pair: {
Ast_Node* operator;
if (node->value.pair->first->type != Ast_Node_Type_Built_In_Function) {
if (node->value.pair->first->type != Ast_Node_Type_Built_In_Function &&
node->value.pair->first->type != Ast_Node_Type_Function)
{
try {
operator = eval_expr(node->value.pair->first, env);
}
@@ -465,6 +595,23 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
case Built_In_Equal: {
return built_in_equals(evaluated_arguments);
}
case Built_In_Load: {
try {
arguments_length = list_length(arguments);
}
if (arguments_length != 1)
report_error(Error_Type_Wrong_Number_Of_Arguments);
if (evaluated_arguments->value.pair->first->type != Ast_Node_Type_String)
report_error(Error_Type_Type_Missmatch);
Ast_Node* result;
try {
result = built_in_load(
evaluated_arguments->value.pair->first->value.string->value, env);
}
return result;
}
case Built_In_Pair: {
if (arguments_length != 2) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
@@ -525,7 +672,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
}
print(evaluated_arguments->value.pair->first);
printf("\n");
/* printf("\n"); */
return arguments->value.pair->first;
}
case Built_In_Read: {
@@ -582,7 +729,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
}
// assume it's lambda function and evaluate the arguments
arguments = eval_arguments(arguments, env, &arguments_length);
try {
arguments = eval_arguments(arguments, env, &arguments_length);
}
if (operator->type == Ast_Node_Type_Function) {
Ast_Node* result;
try {
@@ -592,9 +741,11 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
}
}
default:
default: {
printf("alskjdalskdjaldskjalk");
report_error(Error_Type_Not_A_Function);
}
}
#undef report_error
}
+29
View File
@@ -14,6 +14,35 @@
} \
else label(body,__LINE__):
#define define_array_list(type, name) \
typedef struct { \
type* data; \
int length; \
int next_index; \
} name##_Array_List; \
\
\
void append_to_##name##_array_list(name##_Array_List* arraylist, type element) { \
if (arraylist->next_index == arraylist->length) { \
arraylist->length *= 2; \
arraylist->data = \
(type*)realloc(arraylist->data, arraylist->length * sizeof(type)); \
} \
arraylist->data[arraylist->next_index++] = element; \
} \
\
\
name##_Array_List* create_##name##_array_list(int initial_capacity) { \
name##_Array_List* ret = new(name##_Array_List); \
ret->data = (type*)malloc(initial_capacity * sizeof(type)); \
ret->next_index = 0; \
ret->length = initial_capacity; \
return ret; \
}
define_array_list(char*, String);
typedef enum { false, true } bool;
int string_equal(char* a, char* b) {
+1 -1
View File
@@ -59,7 +59,7 @@ void print(Ast_Node* node) {
printf("%f", node->value.number->value);
} break;
case (Ast_Node_Type_String): {
printf("\"%s\"", node->value.string->value);
printf("%s", node->value.string->value);
} break;
case (Ast_Node_Type_Symbol): {
printf("%s", node->value.symbol->identifier);
+15 -2
View File
@@ -24,6 +24,13 @@ int interprete_file (char* file_content) {
return 1;
}
Environment* env = create_empty_environment();
built_in_load("pre.slime", env);
if (error) {
log_error();
return 1;
}
Ast_Node* result = create_ast_node_nil();
for (int i = 0; i < program->next_index; ++i) {
result = eval_expr(program->data[i], env);
@@ -32,8 +39,7 @@ int interprete_file (char* file_content) {
return 1;
}
}
/* print(result); */
/* printf("\n"); */
return 0;
}
@@ -41,6 +47,13 @@ int interprete_stdin () {
printf("Welcome to the lispy interpreter.\n");
char* line;
Environment* env = create_empty_environment();
built_in_load("pre.slime", env);
if (error) {
log_error();
delete_error();
}
Ast_Node* parsed, * evaluated;
while (true) {
printf(">");