Can now parse lambda lists

This commit is contained in:
FelixBrendel
2018-10-15 00:46:09 +02:00
parent 2006e3b45c
commit f6c2219bd5
15 changed files with 1013 additions and 48 deletions
+69 -12
View File
@@ -36,14 +36,77 @@ typedef struct {
} Pair;
typedef struct {
Pair* regular_params;
Pair* keyword_params;
} Lambda_List;
struct Ast_Node** data;
int length;
int next_index;
} Ast_Node_Array_List;
typedef struct {
Lambda_List* parameters;
Pair* form;
char* docstring;
char** identifiers;
int next_index;
int length;
} Positional_Arguments;
typedef struct {
char** identifiers;
// values[i] will be nullptr if no defalut value was declared for
// key identifiers[i]
Ast_Node_Array_List* values;
int next_index;
int length;
} 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);
Positional_Arguments* create_positional_argument_list(int initial_capacity) {
Positional_Arguments* ret = new(Positional_Arguments);
ret->identifiers = (char**)malloc(initial_capacity * sizeof(char*));
ret->next_index = 0;
ret->length = initial_capacity;
return ret;
}
void append_to_positional_argument_list(Positional_Arguments* args, char* identifier) {
if (args->next_index == args->length) {
args->length *= 2;
args->identifiers = (char**)realloc(args->identifiers, args->length * sizeof(char*));
}
args->identifiers[args->next_index++] = identifier;
}
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->next_index = 0;
ret->length = initial_capacity;
return ret;
}
void append_to_keyword_argument_list(Keyword_Arguments* args,
char* identifier,
struct Ast_Node* default_value)
{
if (args->next_index == args->length) {
args->length *= 2;
args->identifiers = (char**)realloc(args->identifiers, args->length * sizeof(char*));
}
args->identifiers[args->next_index++] = identifier;
append_to_Ast_Node_Array_List(args->values, default_value);
}
typedef struct {
char* docstring;
Positional_Arguments* positional_arguments;
Keyword_Arguments* keyword_arguments;
// rest_argument will be nullptr if no rest argument is declared
char* rest_argument;
struct Ast_Node* body; // implicit prog
} Function;
typedef enum {
@@ -134,12 +197,6 @@ struct Ast_Node {
// was forward declarated
typedef struct Ast_Node Ast_Node;
typedef struct {
Ast_Node** data;
int length;
int next_index;
} Ast_Node_Array_List;
typedef struct {
Ast_Node_Array_List* positional_arguments;
// TODO(Felix): Really use hashmap (keyword[sting] ->
+2
View File
@@ -1,6 +1,7 @@
typedef enum {
Error_Type_Ill_Formed_List,
Error_Type_Ill_Formed_Arguments,
Error_Type_Ill_Formed_Lambda_List,
Error_Type_Wrong_Number_Of_Arguments,
Error_Type_Unknown_Keyword_Argument,
Error_Type_Type_Missmatch,
@@ -40,6 +41,7 @@ char* Error_Type_to_string(Error_Type type) {
switch (type) {
case Error_Type_Ill_Formed_List: return "Evaluation-error: Ill formed list";
case Error_Type_Ill_Formed_Arguments: return "Evaluation-error: Ill formed arguments";
case Error_Type_Ill_Formed_Lambda_List: return "Evaluation-error: Ill formed lambda list";
case Error_Type_Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument";
case Error_Type_Not_A_Function: return "Evaluation-error: Not a function";
case Error_Type_Symbol_Not_Defined: return "Evaluation-error: Symbol not defined";
+190 -6
View File
@@ -1,7 +1,140 @@
/* Ast_Node* apply_to_lambda () {} */
Ast_Node* eval_expr(Ast_Node* node, Environment* env);
bool is_truthy (Ast_Node* expression, Environment* env);
Ast_Node* apply_arguments_to_function (Ast_Node* arguments, Ast_Node* function) {
printf("calling function, yey\n");
return create_ast_node_nil();
}
/**
This parses the argument specification of funcitons into their
Function struct. It dois this by allocating new
positional_arguments, keyword_arguments and rest_argument and
filling it in
*/
void parse_argument_list(Ast_Node* arguments, Function* function) {
// first init the fields
function->positional_arguments = create_positional_argument_list(16);
function->keyword_arguments = create_keyword_argument_list(16);
function->rest_argument = nullptr;
// okay let's try to read some positional arguments
while (arguments->type == Ast_Node_Type_Pair) {
if (arguments->value.pair->first->type == Ast_Node_Type_Keyword) {
if (string_equal(arguments->value.pair->first->value.keyword->identifier, "keys") ||
string_equal(arguments->value.pair->first->value.keyword->identifier, "rest"))
break;
else {
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
}
if (arguments->value.pair->first->type != Ast_Node_Type_Symbol) {
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
// okay wow we found an actual symbol
append_to_positional_argument_list(
function->positional_arguments,
arguments->value.pair->first->value.symbol->identifier);
arguments = arguments->value.pair->rest;
}
// okay we are done with positional arguments, lets check for
// keywords,
if (arguments->type != Ast_Node_Type_Pair) {
if (arguments->type != Ast_Node_Type_Nil)
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
if (arguments->value.pair->first->type == Ast_Node_Type_Keyword &&
string_equal(arguments->value.pair->first->value.keyword->identifier, "keys"))
{
arguments = arguments->value.pair->rest;
if (arguments->type != Ast_Node_Type_Pair ||
arguments->value.pair->first->type != Ast_Node_Type_Symbol)
{
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
while (arguments->type == Ast_Node_Type_Pair) {
if (arguments->value.pair->first->type == Ast_Node_Type_Keyword) {
if (string_equal(arguments->value.pair->first->value.keyword->identifier, "rest"))
break;
else {
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
}
if (arguments->value.pair->first->type != Ast_Node_Type_Symbol) {
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
// we found a symbol (arguments->value.pair->first) for
// the keyword args! Let's check if the next arguement is
// :defaults-to
Ast_Node* next = arguments->value.pair->rest;
if (next->type == Ast_Node_Type_Pair &&
next->value.pair->first->type == Ast_Node_Type_Keyword &&
string_equal(next->value.pair->first->value.keyword->identifier,
"defaults-to"))
{
// check if there is a next argument too, otherwise it
// would be an error
next = next->value.pair->rest;
if (next->type == Ast_Node_Type_Pair) {
append_to_keyword_argument_list(function->keyword_arguments,
arguments->value.pair->first->value.symbol->identifier,
next->value.pair->first);
arguments = next->value.pair->rest;
} else {
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
} else {
// No :defaults-to, so just add it to the list
append_to_keyword_argument_list(function->keyword_arguments,
arguments->value.pair->first->value.symbol->identifier,
nullptr);
arguments = next;
}
}
}
// Now we are also done with keyword arguments, lets check for
// if there is a rest argument
if (arguments->type != Ast_Node_Type_Pair) {
if (arguments->type != Ast_Node_Type_Nil)
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
if (arguments->value.pair->first->type == Ast_Node_Type_Keyword &&
string_equal(arguments->value.pair->first->value.keyword->identifier, "rest"))
{
arguments = arguments->value.pair->rest;
if (arguments->type != Ast_Node_Type_Pair ||
arguments->value.pair->first->type != Ast_Node_Type_Symbol)
{
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
return;
}
function->rest_argument = arguments->value.pair->first->value.symbol->identifier;
if (arguments->value.pair->rest->type != Ast_Node_Type_Nil) {
create_error(Error_Type_Ill_Formed_Lambda_List, arguments);
}
} else {
printf("this should not happen?");
create_error(Error_Type_Unknown_Error, arguments);
}
}
int list_length(Ast_Node* node) {
@@ -56,6 +189,9 @@ Ast_Node* copy_list(Ast_Node* node) {
return result;
}
Ast_Node* eval_expr(Ast_Node* node, Environment* env);
bool is_truthy (Ast_Node* expression, Environment* env);
Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env) {
// TODO(Felix): if arguments is nil then maybe return a constant
// Parsed_Arguments_nil?
@@ -70,9 +206,9 @@ Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env
Parse_State parse_state = Expecting_Anything;
Parsed_Arguments* result = new(Parsed_Arguments);
result->positional_arguments = create_Ast_Node_Array_List();
result->keyword_keys = create_Ast_Node_Array_List();
result->keyword_values = create_Ast_Node_Array_List();
result->positional_arguments = create_Ast_Node_Array_List(16);
result->keyword_keys = create_Ast_Node_Array_List(16);
result->keyword_values = create_Ast_Node_Array_List(16);
Ast_Node* current_head = copy_list(arguments);
Ast_Node* current_evaluated_head;
@@ -171,6 +307,47 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
// check for special form
if (operator->type == Ast_Node_Type_Built_In_Function) {
switch (operator->value.built_in_function->type) {
case Built_In_Lambda: {
/*
* (lambda ())
* (lambda (x d) (+ 1 2) (- 1 2) (* 1 2))
*/
try {
arguments_length = list_length(arguments);
}
if (arguments_length == 0)
report_error(Error_Type_Wrong_Number_Of_Arguments);
Function* function = new(Function);
// if parameters were specified
if (arguments->value.pair->first->type != Ast_Node_Type_Nil) {
try {
assert_type(arguments->value.pair->first, Ast_Node_Type_Pair);
}
try {
parse_argument_list(arguments->value.pair->first, function);
}
}
arguments = arguments->value.pair->rest;
// if there is a docstring, use it
if (arguments->value.pair->first->type == Ast_Node_Type_String) {
function->docstring = arguments->value.pair->first->value.string->value;
arguments = arguments->value.pair->rest;
}
// we are now in the function body, just wrap it in an
// implicit prog
function->body = create_ast_node_pair(
create_ast_node_built_in_function("prog"),
arguments);
Ast_Node* ret = new(Ast_Node);
ret->type = Ast_Node_Type_Function;
ret->value.function = function;
return ret;
}
case Built_In_And: {
bool result = true;
while (arguments->type != Ast_Node_Type_Nil) {
@@ -454,6 +631,13 @@ 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);
if (operator->type == Ast_Node_Type_Function) {
Ast_Node* result;
try {
result = apply_arguments_to_function(arguments, operator);
}
return result;
}
}
default:
+1 -1
View File
@@ -14,5 +14,5 @@ void init () {
#endif
// TODO(Felix): Init the constants here (Bulit-in function
// ast_nodes, nil, ..more?)
// ast_nodes, nil, type_keywords ..more?)
}
+1
View File
@@ -69,6 +69,7 @@ void print(Ast_Node* node) {
} break;
case (Ast_Node_Type_Function): {
printf("[lambda]");
/* print(node->value.function->body); */
} break;
case (Ast_Node_Type_Built_In_Function): {
printf("[built-in-function %s]", Built_In_Name_to_string(node->value.built_in_function->type));
+7 -6
View File
@@ -1,22 +1,23 @@
Ast_Node_Array_List* create_Ast_Node_Array_List() {
Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length) {
Ast_Node_Array_List* ret = new (Ast_Node_Array_List);
// create one with 16 entries first
ret->length = 16;
ret->data = (Ast_Node**)malloc(ret->length * sizeof(Ast_Node));
ret->length = initial_length;
ret->data = (struct Ast_Node**)malloc(initial_length * sizeof(struct Ast_Node));
ret->next_index = 0;
return ret;
}
void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, Ast_Node* node) {
void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, struct Ast_Node* node) {
if (list->next_index == list->length) {
list->length *= 2;
list->data = (Ast_Node**)realloc(list->data, list->length * sizeof(Ast_Node));
list->data = (struct Ast_Node**)realloc(list->data, list->length * sizeof(struct Ast_Node));
}
list->data[list->next_index++] = node;
}
void eat_comment_line(char* text, int* index_in_text) {
// safety check if we are actually starting a comment here
if (text[*index_in_text] != ';')
@@ -237,7 +238,7 @@ Ast_Node* parse_single_expression(char* text) {
}
Ast_Node_Array_List* parse_program(char* text) {
Ast_Node_Array_List* program = create_Ast_Node_Array_List();
Ast_Node_Array_List* program = create_Ast_Node_Array_List(16);
int index_in_text = 0;