Can now parse lambda lists
This commit is contained in:
@@ -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] ->
|
||||
|
||||
@@ -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
@@ -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
@@ -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?)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user