瀏覽代碼

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

master
FelixBrendel 7 年之前
父節點
當前提交
488b47f08f
共有 10 個文件被更改,包括 306 次插入21 次删除
  1. +73
    -0
      bin/pre.slime
  2. +0
    -1
      bin/test.slime
  3. +1
    -1
      build.bat
  4. +7
    -11
      src/ast.c
  5. +23
    -0
      src/built_ins.c
  6. +1
    -0
      src/env.c
  7. +156
    -5
      src/eval.c
  8. +29
    -0
      src/helpers.c
  9. +1
    -1
      src/io.c
  10. +15
    -2
      src/main.c

+ 73
- 0
bin/pre.slime 查看文件

@@ -0,0 +1,73 @@
(define nil ())

(define nil?
(lambda (x)
"Checks if the argument is nil."
(= x nil)))

(define append
(lambda (obj sequence)
(if (nil? sequence)
(list obj)
(if (nil? (rest sequence))
))))

(define range
(lambda (:keys from :defaults-to 0 to)
"Returns a sequence of numbers starting with the number
defined by the key 'from' and ends with the number defined in
'to'."
(if (<= from to)
(pair from (range :from (+ 1 from) :to to))
nil)))

(define map
(lambda (function sequence)
"Takes a sequence and a function as arguments and returns a
new sequence which contains the results of using the first
sequences elemens as argument to that function."
(if (nil? sequence)
sequence
(pair (function (first sequence))
(map (rest sequence) function)))))

(define reduce
(lambda (function sequence)
"Takes a sequence and a function as arguments and applies the
function to the argument sequence. This only works correctly if the
given function accepts a variable amount of parameters. If your
funciton is limited to two arguments, use `reduce-binary' instead."
(eval (pair function sequence))))

(define reduce-binary
(lambda (function sequence)
"Takes a sequence and a function as arguments and applies the
function to the argument sequence. reduce-binary applies the
arguments `pair-wise' which means it works with binary functions
as compared to `reduce'."
(if (nil? (rest sequence))
(first sequence)
(function (first sequence)
(reduce-binary (rest sequence) function)))))

(define filter
(lambda (function sequence)
(if (nil? sequence)
nil
(if (function (first sequence))
(pair (first sequence)
(filter (rest sequence) function))
(filter (rest sequence) function)))))

(define printf
(lambda (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
(if (and (nil? (first args)) (nil? (rest args)))
(print end)
(prog
(print (first args))
(if (not (nil? (rest args)))
(print sep))
;; TODO(Felix): later we should use `extend' here:
;; (eval (extend (quote (printf :sep sep :end end)) (rest args)))
(eval (pair printf (pair :sep (pair sep (pair :end (pair end (rest args)))))))
nil))))

+ 0
- 1
bin/test.slime 查看文件

@@ -1,2 +1 @@
(define operators (list + - * /))
(print ((first operators) 1 2 3))

+ 1
- 1
build.bat 查看文件

@@ -11,7 +11,7 @@ pushd quickbuild
taskkill /F /IM %exeName% > NUL 2> NUL

echo ---------- Compiling ----------
call timecmd cl ../src/main.c /Fe%exeName% /W3 /TC /nologo /EHsc /Z7 /link /incremental /debug:fastlink
call timecmd cl ../src/main.c /Fe%exeName% /W3 /Ox /O2 /Oi /TC /nologo /EHsc /link

if %errorlevel% == 0 (
echo.


+ 7
- 11
src/ast.c 查看文件

@@ -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
- 0
src/built_ins.c 查看文件

@@ -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
- 0
src/env.c 查看文件

@@ -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
src/eval.c 查看文件

@@ -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
- 0
src/helpers.c 查看文件

@@ -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
src/io.c 查看文件

@@ -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
src/main.c 查看文件

@@ -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(">");


Loading…
取消
儲存