Use the parse arguments
This commit is contained in:
+2
-9
@@ -1,13 +1,6 @@
|
||||
void assert_type (Ast_Node* node, Ast_Node_Type type) {
|
||||
if (!node)
|
||||
create_error(Error_Type_Unknown_Error, node);
|
||||
if (node->type == type) return;
|
||||
|
||||
/* char *wanted, *got, *message; */
|
||||
/* wanted = Ast_Node_Type_to_string(type); */
|
||||
/* got = Ast_Node_Type_to_string(node->type); */
|
||||
/* asprintf(&message, "Type assertion failed:\n\t" */
|
||||
/* "Wanted: %s\n\t" */
|
||||
/* "Got : %s\n", wanted, got); */
|
||||
/* panic(message); */
|
||||
|
||||
create_error(Error_Type_Type_Missmatch, node);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,19 @@ 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] ->
|
||||
// value[Ast_Node*]) here
|
||||
Ast_Node_Array_List* keyword_keys;
|
||||
Ast_Node_Array_List* keyword_values;
|
||||
} Parsed_Arguments;
|
||||
|
||||
Ast_Node* create_ast_node_nil() {
|
||||
Ast_Node* node = new(Ast_Node);
|
||||
|
||||
+47
-47
@@ -39,84 +39,84 @@ bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast_Node* built_in_equals(Ast_Node* operands) {
|
||||
if (operands->type == Ast_Node_Type_Nil)
|
||||
return create_ast_node_number(1);
|
||||
|
||||
Ast_Node* first = operands->value.pair->first;
|
||||
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
if (!ast_node_equal(operands->value.pair->first, first))
|
||||
Ast_Node* built_in_equals(Parsed_Arguments* arguments) {
|
||||
for (int i = 0; i < arguments->positional_arguments->next_index-1; ++i) {
|
||||
if (!ast_node_equal(
|
||||
arguments->positional_arguments->data[i],
|
||||
arguments->positional_arguments->data[i+1]))
|
||||
return create_ast_node_nil();
|
||||
operands = operands->value.pair->rest;
|
||||
}
|
||||
|
||||
return create_ast_node_number(1);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_add(Ast_Node* operands) {
|
||||
Ast_Node* built_in_add(Parsed_Arguments* arguments) {
|
||||
double sum = 0;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
for (int i = 0; i < arguments->positional_arguments->next_index; ++i) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number);
|
||||
}
|
||||
sum += operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
sum += arguments->positional_arguments->data[i]->value.number->value;
|
||||
}
|
||||
|
||||
return create_ast_node_number(sum);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_substract(Ast_Node* operands) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
}
|
||||
double difference = operands->value.pair->first->value.number->value;
|
||||
Ast_Node* built_in_substract(Parsed_Arguments* arguments) {
|
||||
if (arguments->positional_arguments->next_index == 0)
|
||||
return create_ast_node_number(0);
|
||||
|
||||
operands = operands->value.pair->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
assert_type(*arguments->positional_arguments->data, Ast_Node_Type_Number);
|
||||
}
|
||||
|
||||
difference -= operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
if (arguments->positional_arguments->next_index == 1) {
|
||||
return create_ast_node_number(-(*arguments->positional_arguments->data)->value.number->value);
|
||||
}
|
||||
|
||||
// okay we have at least 2 arguments
|
||||
double difference = (*arguments->positional_arguments->data)->value.number->value;
|
||||
for (int i = 1; i < arguments->positional_arguments->next_index; ++i) {
|
||||
try {
|
||||
assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number);
|
||||
}
|
||||
difference -= arguments->positional_arguments->data[i]->value.number->value;
|
||||
}
|
||||
|
||||
return create_ast_node_number(difference);
|
||||
}
|
||||
|
||||
Ast_Node* built_in_multiply(Ast_Node* operands) {
|
||||
Ast_Node* built_in_multiply(Parsed_Arguments* arguments) {
|
||||
double product = 1;
|
||||
for (int i = 0; i < arguments->positional_arguments->next_index; ++i) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number);
|
||||
}
|
||||
double product = operands->value.pair->first->value.number->value;
|
||||
|
||||
operands = operands->value.pair->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
product *= arguments->positional_arguments->data[i]->value.number->value;
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
}
|
||||
double quotient = operands->value.pair->first->value.number->value;
|
||||
Ast_Node* built_in_divide(Parsed_Arguments* arguments) {
|
||||
if (arguments->positional_arguments->next_index == 0)
|
||||
return create_ast_node_number(1);
|
||||
|
||||
operands = operands->value.pair->rest;
|
||||
while (operands->type == Ast_Node_Type_Pair) {
|
||||
try {
|
||||
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
|
||||
assert_type(*arguments->positional_arguments->data, Ast_Node_Type_Number);
|
||||
}
|
||||
|
||||
quotient /= operands->value.pair->first->value.number->value;
|
||||
operands = operands->value.pair->rest;
|
||||
if (arguments->positional_arguments->next_index == 1) {
|
||||
return create_ast_node_number((*arguments->positional_arguments->data)->value.number->value);
|
||||
}
|
||||
return create_ast_node_number(quotient);
|
||||
|
||||
// okay we have at least 2 arguments
|
||||
double difference = (*arguments->positional_arguments->data)->value.number->value;
|
||||
for (int i = 1; i < arguments->positional_arguments->next_index; ++i) {
|
||||
try {
|
||||
assert_type(arguments->positional_arguments->data[i], Ast_Node_Type_Number);
|
||||
}
|
||||
difference /= arguments->positional_arguments->data[i]->value.number->value;
|
||||
}
|
||||
|
||||
return create_ast_node_number(difference);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ typedef enum {
|
||||
Error_Type_Ill_Formed_List,
|
||||
Error_Type_Ill_Formed_Arguments,
|
||||
Error_Type_Wrong_Number_Of_Arguments,
|
||||
Error_Type_Unknown_Keyword_Argument,
|
||||
Error_Type_Type_Missmatch,
|
||||
Error_Type_Symbol_Not_Defined,
|
||||
Error_Type_Not_A_Function,
|
||||
@@ -39,6 +40,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_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";
|
||||
case Error_Type_Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments";
|
||||
|
||||
+54
-17
@@ -56,14 +56,6 @@ Ast_Node* copy_list(Ast_Node* node) {
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Ast_Node_Array_List* positional_arguments;
|
||||
// TODO(Felix): Really use hashmap (keyword[sting] ->
|
||||
// value[Ast_Node*]) here
|
||||
Ast_Node_Array_List* keyword_keys;
|
||||
Ast_Node_Array_List* keyword_values;
|
||||
} Parsed_Arguments;
|
||||
|
||||
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?
|
||||
@@ -114,6 +106,15 @@ Parsed_Arguments* eval_and_parse_arguments(Ast_Node* arguments, Environment* env
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast_Node* extract_keyword_value(char* keyword, Parsed_Arguments* args) {
|
||||
// NOTE(Felix): This will be a hashmap lookup later
|
||||
for (int i = 0; i < args->keyword_keys->next_index; ++i) {
|
||||
if (string_equal(args->keyword_keys->data[i]->value.keyword->identifier, keyword))
|
||||
return args->keyword_values->data[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_arguments_length) {
|
||||
*out_arguments_length = 0;
|
||||
if (arguments->type == Ast_Node_Type_Nil) {
|
||||
@@ -279,25 +280,27 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
// to evaluate the arguments; eval_arguments will also tell
|
||||
// us the arguments_length.
|
||||
Ast_Node* evaluated_arguments;
|
||||
Parsed_Arguments* evaluated_and_parsed_arguments;
|
||||
try {
|
||||
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||
evaluated_and_parsed_arguments = eval_and_parse_arguments(arguments, env);
|
||||
}
|
||||
|
||||
switch (operator->value.built_in_function->type) {
|
||||
case Built_In_Addition: {
|
||||
return built_in_add(evaluated_arguments);
|
||||
return built_in_add(evaluated_and_parsed_arguments);
|
||||
}
|
||||
case Built_In_Subtraction: {
|
||||
return built_in_substract(evaluated_arguments);
|
||||
return built_in_substract(evaluated_and_parsed_arguments);
|
||||
}
|
||||
case Built_In_Multiplication: {
|
||||
return built_in_multiply(evaluated_arguments);
|
||||
return built_in_multiply(evaluated_and_parsed_arguments);
|
||||
}
|
||||
case Built_In_Division: {
|
||||
return built_in_divide(evaluated_arguments);
|
||||
return built_in_divide(evaluated_and_parsed_arguments);
|
||||
}
|
||||
case Built_In_Equal: {
|
||||
return built_in_equals(evaluated_arguments);
|
||||
return built_in_equals(evaluated_and_parsed_arguments);
|
||||
}
|
||||
case Built_In_Pair: {
|
||||
if (arguments_length != 2) {
|
||||
@@ -355,12 +358,46 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
||||
return evaluated_arguments;
|
||||
}
|
||||
case Built_In_Print: {
|
||||
if (arguments_length != 1) {
|
||||
/* if (arguments_length != 1) { */
|
||||
/* report_error(Error_Type_Wrong_Number_Of_Arguments); */
|
||||
/* } */
|
||||
/* print(evaluated_arguments->value.pair->first); */
|
||||
/* printf("\n"); */
|
||||
/* return arguments->value.pair->first; */
|
||||
|
||||
if (evaluated_and_parsed_arguments->positional_arguments->next_index == 0) {
|
||||
report_error(Error_Type_Wrong_Number_Of_Arguments);
|
||||
}
|
||||
print(evaluated_arguments->value.pair->first);
|
||||
printf("\n");
|
||||
return arguments->value.pair->first;
|
||||
|
||||
char* sep = " ";
|
||||
char* end = "\n";
|
||||
|
||||
Ast_Node* temp = extract_keyword_value("sep", evaluated_and_parsed_arguments);
|
||||
if (temp) {
|
||||
try {
|
||||
assert_type(temp, Ast_Node_Type_String);
|
||||
}
|
||||
sep = temp->value.string->value;
|
||||
}
|
||||
|
||||
temp = extract_keyword_value("end", evaluated_and_parsed_arguments);
|
||||
if (temp) {
|
||||
try {
|
||||
assert_type(temp, Ast_Node_Type_String);
|
||||
}
|
||||
end = temp->value.string->value;
|
||||
}
|
||||
|
||||
print(*evaluated_and_parsed_arguments->positional_arguments->data);
|
||||
for (int i = 1; i < evaluated_and_parsed_arguments->positional_arguments->next_index; ++i) {
|
||||
printf("%s", sep);
|
||||
print(*(evaluated_and_parsed_arguments->positional_arguments->data+i));
|
||||
}
|
||||
printf("%s", end);
|
||||
|
||||
// return last positional argument
|
||||
return *(evaluated_and_parsed_arguments->positional_arguments->data+
|
||||
(evaluated_and_parsed_arguments->positional_arguments->next_index-1));
|
||||
}
|
||||
case Built_In_Read: {
|
||||
if (arguments_length > 1) {
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// for colored console output
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#pragma comment(lib, "Kernel32.lib")
|
||||
#endif
|
||||
|
||||
void init () {
|
||||
// On Windows: manually enable colored console output
|
||||
#ifdef _WIN32
|
||||
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
ENABLE_PROCESSED_OUTPUT |
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT |
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
#endif
|
||||
|
||||
// TODO(Felix): Init the constants here (Bulit-in function
|
||||
// ast_nodes, nil, ..more?)
|
||||
}
|
||||
+3
-1
@@ -15,6 +15,7 @@
|
||||
#include "./built_ins.c"
|
||||
#include "./eval.c"
|
||||
#include "./testing.c"
|
||||
#include "./init.c"
|
||||
|
||||
int interprete_file (char* file_content) {
|
||||
Ast_Node_Array_List* program = parse_program(file_content);
|
||||
@@ -62,8 +63,9 @@ int interprete_stdin () {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
init();
|
||||
|
||||
if (argc > 1) {
|
||||
char* file_content = read_entire_file(argv[1]);
|
||||
if (file_content) {
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
typedef struct {
|
||||
Ast_Node** data;
|
||||
int length;
|
||||
int next_index;
|
||||
} Ast_Node_Array_List;
|
||||
|
||||
Ast_Node_Array_List* create_Ast_Node_Array_List() {
|
||||
Ast_Node_Array_List* ret = new (Ast_Node_Array_List);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user