FelixBrendel 8 лет назад
Родитель
Сommit
1ea4cf5213
8 измененных файлов: 313 добавлений и 73 удалений
  1. +2
    -0
      build.bat
  2. +9
    -7
      src/assert.c
  3. +78
    -7
      src/built_ins.c
  4. +6
    -6
      src/env.c
  5. +159
    -39
      src/eval.c
  6. +15
    -1
      src/helpers.c
  7. +4
    -3
      src/parse.c
  8. +40
    -10
      todo.org

+ 2
- 0
build.bat Просмотреть файл

@@ -8,6 +8,8 @@ set binDir=bin
mkdir quickbuild 2>nul mkdir quickbuild 2>nul
pushd quickbuild pushd quickbuild


taskkill /F /IM %exeName% > NUL 2> NUL

echo ---------- Compiling ---------- 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 /TC /nologo /EHsc /Z7 /link /incremental /debug:fastlink




+ 9
- 7
src/assert.c Просмотреть файл

@@ -1,11 +1,13 @@
void assert_type (Ast_Node* node, Ast_Node_Type type) { void assert_type (Ast_Node* node, Ast_Node_Type type) {
if (node->type == type) return; 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);
/* 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);
} }

+ 78
- 7
src/built_ins.c Просмотреть файл

@@ -1,7 +1,66 @@
bool ast_node_equal(Ast_Node* n1, Ast_Node* n2) {
if (n1 == n2)
return true;
if (n1->type != n2->type)
return false;

switch (n1->type) {
case Ast_Node_Type_Built_In_Function:
return string_equal(
n1->value.built_in_function->identifier,
n2->value.built_in_function->identifier);
case Ast_Node_Type_Function:
// if they have the same pointer, true is
// returned a few lines above
return false;
case Ast_Node_Type_Keyword:
return string_equal(
n1->value.keyword->identifier,
n2->value.keyword->identifier);
case Ast_Node_Type_Nil:
return true;
case Ast_Node_Type_Number:
return
n1->value.number->value ==
n2->value.number->value;
case Ast_Node_Type_Pair:
create_error(Error_Type_Not_Yet_Implemented, n1);
return false;
case Ast_Node_Type_String:
return string_equal(
n1->value.string->value,
n2->value.string->value);
case Ast_Node_Type_Symbol:
return string_equal(
n1->value.symbol->identifier,
n2->value.symbol->identifier);
}

// we should never reach here
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))
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(Ast_Node* operands) {
double sum = 0; double sum = 0;
while (operands->type == Ast_Node_Type_Pair) { while (operands->type == Ast_Node_Type_Pair) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}
sum += operands->value.pair->first->value.number->value; sum += operands->value.pair->first->value.number->value;
operands = operands->value.pair->rest; operands = operands->value.pair->rest;
} }
@@ -10,12 +69,16 @@ Ast_Node* built_in_add(Ast_Node* operands) {
} }


Ast_Node* built_in_substract(Ast_Node* operands) { Ast_Node* built_in_substract(Ast_Node* operands) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}
double difference = operands->value.pair->first->value.number->value; double difference = operands->value.pair->first->value.number->value;


operands = operands->value.pair->rest; operands = operands->value.pair->rest;
while (operands->type == Ast_Node_Type_Pair) { while (operands->type == Ast_Node_Type_Pair) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}


difference -= operands->value.pair->first->value.number->value; difference -= operands->value.pair->first->value.number->value;
operands = operands->value.pair->rest; operands = operands->value.pair->rest;
@@ -24,12 +87,16 @@ Ast_Node* built_in_substract(Ast_Node* operands) {
} }


Ast_Node* built_in_multiply(Ast_Node* operands) { Ast_Node* built_in_multiply(Ast_Node* operands) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}
double product = operands->value.pair->first->value.number->value; double product = operands->value.pair->first->value.number->value;


operands = operands->value.pair->rest; operands = operands->value.pair->rest;
while (operands->type == Ast_Node_Type_Pair) { while (operands->type == Ast_Node_Type_Pair) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}


product *= operands->value.pair->first->value.number->value; product *= operands->value.pair->first->value.number->value;
operands = operands->value.pair->rest; operands = operands->value.pair->rest;
@@ -38,12 +105,16 @@ Ast_Node* built_in_multiply(Ast_Node* operands) {
} }


Ast_Node* built_in_divide(Ast_Node* operands) { Ast_Node* built_in_divide(Ast_Node* operands) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}
double quotient = operands->value.pair->first->value.number->value; double quotient = operands->value.pair->first->value.number->value;


operands = operands->value.pair->rest; operands = operands->value.pair->rest;
while (operands->type == Ast_Node_Type_Pair) { while (operands->type == Ast_Node_Type_Pair) {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
try {
assert_type(operands->value.pair->first, Ast_Node_Type_Number);
}


quotient /= operands->value.pair->first->value.number->value; quotient /= operands->value.pair->first->value.number->value;
operands = operands->value.pair->rest; operands = operands->value.pair->rest;


+ 6
- 6
src/env.c Просмотреть файл

@@ -12,7 +12,7 @@ typedef struct Environment Environment;
Environment* create_empty_environment() { Environment* create_empty_environment() {
Environment* env = new(Environment); Environment* env = new(Environment);


int start_capacity = 1;
int start_capacity = 16;


env->parent = nullptr; env->parent = nullptr;
env->capacity = start_capacity; env->capacity = start_capacity;
@@ -54,17 +54,17 @@ Ast_Node* lookup_symbol(Symbol* sym, Environment* env) {
"+", "-", "*", "/", "+", "-", "*", "/",
">", "<", "=", "<=", ">=", ">", "<", "=", "<=", ">=",
// Conditional stuff // Conditional stuff
"if", "and", "or", "not",
"if", "and", "or", "not",
// Cons stuff // Cons stuff
"first", "rest", "pair",
"pair", "first", "rest",
// rest // rest
"load", "define", "load", "define",
"lambda", "progn", "lambda", "progn",
"eval", "quote",
"eval", "quote", "prog", "list",
"print", "read", "print", "read",
"help", "exit"
"info", "type", "exit"
}; };
int built_in_count = 26;
int built_in_count = sizeof(built_in_names) / sizeof(char*);


for (int i = 0; i < built_in_count; ++i) { for (int i = 0; i < built_in_count; ++i) {
if (string_equal(built_in_names[i], sym->identifier)) { if (string_equal(built_in_names[i], sym->identifier)) {


+ 159
- 39
src/eval.c Просмотреть файл

@@ -56,46 +56,84 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
case Ast_Node_Type_String: case Ast_Node_Type_String:
return node; return node;
case Ast_Node_Type_Pair: { case Ast_Node_Type_Pair: {
Ast_Node* operator = eval_expr(node->value.pair->first, env);
if (error) return nullptr;
Ast_Node* operator;
try {
operator = eval_expr(node->value.pair->first, env);
}


Ast_Node* operands = node->value.pair->rest; Ast_Node* operands = node->value.pair->rest;
int operands_length;



// check for built ins functions // check for built ins functions
if (operator->type == Ast_Node_Type_Built_In_Function) { if (operator->type == Ast_Node_Type_Built_In_Function) {
char* operator_name = operator->value.built_in_function->identifier; char* operator_name = operator->value.built_in_function->identifier;
if (string_equal("quote", operator_name)) { if (string_equal("quote", operator_name)) {
int operands_length = list_length(operands);
operands_length = list_length(operands);
if (operands_length != 1) { if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }
return operands->value.pair->first; return operands->value.pair->first;
} else if (string_equal("eval", operator_name)) { } else if (string_equal("eval", operator_name)) {
int operands_length = list_length(operands);
try {
operands_length = list_length(operands);
}
if (operands_length != 1) { if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }
if (error) return nullptr;
return eval_expr(operands->value.pair->first, env); return eval_expr(operands->value.pair->first, env);
} else if (string_equal("prog", operator_name)) {
if (operands->type == Ast_Node_Type_Nil)
return operands;
while (!error) {
try {
operands->value.pair->first = eval_expr(operands->value.pair->first, env);
}

if (operands->value.pair->rest->type == Ast_Node_Type_Pair)
operands = operands->value.pair->rest;
else {
if (operands->value.pair->rest->type != Ast_Node_Type_Nil)
report_error(Error_Type_Ill_Formed_List);
break;
}
}
return operands->value.pair->first;
} else if (string_equal("list", operator_name)) {
try {
eval_operands(operands, env);
}
return operands;
} else if (string_equal("=", operator_name)) {
try {
eval_operands(operands, env);
}
return built_in_equals(operands);
} else if (string_equal("+", operator_name)) { } else if (string_equal("+", operator_name)) {
eval_operands(operands, env);
if (error) return nullptr;
try {
eval_operands(operands, env);
}
return built_in_add(operands); return built_in_add(operands);
} else if (string_equal("-", operator_name)) { } else if (string_equal("-", operator_name)) {
eval_operands(operands, env);
if (error) return nullptr;
try {
eval_operands(operands, env);
}
return built_in_substract(operands); return built_in_substract(operands);
} else if (string_equal("*", operator_name)) { } else if (string_equal("*", operator_name)) {
eval_operands(operands, env);
if (error) return nullptr;
try {
eval_operands(operands, env);
}
return built_in_multiply(operands); return built_in_multiply(operands);
} else if (string_equal("/", operator_name)) { } else if (string_equal("/", operator_name)) {
eval_operands(operands, env);
if (error) return nullptr;
try {
eval_operands(operands, env);
}
return built_in_divide(operands); return built_in_divide(operands);
} else if (string_equal("define", operator_name)) { } else if (string_equal("define", operator_name)) {
int operands_length = list_length(operands);
if (error) return nullptr;
try {
operands_length = list_length(operands);
}
if (operands_length != 2) { if (operands_length != 2) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }
@@ -110,14 +148,40 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
define_symbol(symbol, value, env); define_symbol(symbol, value, env);


return value; return value;
} else if (string_equal("type", operator_name)) {
try {
operands_length = list_length(operands);
}
if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
}
try {
eval_operands(operands, env);
}
Ast_Node_Type type = operands->value.pair->first->type;
switch (type) {
case Ast_Node_Type_Built_In_Function: return create_ast_node_keyword("built-in-function");
case Ast_Node_Type_Function: return create_ast_node_keyword("dynamic-function");
case Ast_Node_Type_Keyword: return create_ast_node_keyword("keyword");
case Ast_Node_Type_Nil: return create_ast_node_keyword("nil");
case Ast_Node_Type_Number: return create_ast_node_keyword("number");
case Ast_Node_Type_Pair: return create_ast_node_keyword("pair");
case Ast_Node_Type_String: return create_ast_node_keyword("string");
case Ast_Node_Type_Symbol: return create_ast_node_keyword("symbol");
}

} else if (string_equal("exit", operator_name)) { } else if (string_equal("exit", operator_name)) {
int operands_length = list_length(operands);
if (error) return nullptr;
try {
operands_length = list_length(operands);
}
if (operands_length > 1) { if (operands_length > 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }


if (operands_length == 1) { if (operands_length == 1) {
try {
eval_operands(operands, env);
}
Ast_Node* error_code = operands->value.pair->first; Ast_Node* error_code = operands->value.pair->first;
if (error_code->type != Ast_Node_Type_Number) if (error_code->type != Ast_Node_Type_Number)
report_error(Error_Type_Type_Missmatch); report_error(Error_Type_Type_Missmatch);
@@ -127,26 +191,30 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
exit(0); exit(0);


} else if (string_equal("print", operator_name)) { } else if (string_equal("print", operator_name)) {
int operands_length = list_length(operands);
if (error) return nullptr;
try {
operands_length = list_length(operands);
}
if (operands_length != 1) { if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }
eval_operands(operands, env);
if (error) return nullptr;
try {
eval_operands(operands, env);
}
print(operands->value.pair->first); print(operands->value.pair->first);
printf("\n"); printf("\n");
return operands->value.pair->first; return operands->value.pair->first;
} else if (string_equal("read", operator_name)) { } else if (string_equal("read", operator_name)) {
int operands_length = list_length(operands);
if (error) return nullptr;
try {
operands_length = list_length(operands);
}
if (operands_length > 1) { if (operands_length > 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }


if (operands_length == 1) { if (operands_length == 1) {
eval_operands(operands, env);
if (error) return nullptr;
try {
eval_operands(operands, env);
}
Ast_Node* prompt = operands->value.pair->first; Ast_Node* prompt = operands->value.pair->first;
if (prompt->type == Ast_Node_Type_String) if (prompt->type == Ast_Node_Type_String)
printf("%s", prompt->value.string->value); printf("%s", prompt->value.string->value);
@@ -155,9 +223,54 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
} }
char* line = read_line(); char* line = read_line();
return create_ast_node_string(line, (int)strlen(line)); return create_ast_node_string(line, (int)strlen(line));
} else if (string_equal("pair", operator_name)) {
try {
operands_length = list_length(operands);
}
if (operands_length != 2) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
}
try {
eval_operands(operands, env);
}

return create_ast_node_pair(operands->value.pair->first, operands->value.pair->rest->value.pair->first);
} else if (string_equal("first", operator_name)) {
try {
operands_length = list_length(operands);
}
if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
}
try {
eval_operands(operands, env);
}
if (operands->value.pair->first->type == Ast_Node_Type_Nil)
return create_ast_node_nil();
if (operands->value.pair->first->type != Ast_Node_Type_Pair)
report_error(Error_Type_Type_Missmatch);

return operands->value.pair->first->value.pair->first;
} else if (string_equal("rest", operator_name)) {
try {
operands_length = list_length(operands);
}
if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
}
try {
eval_operands(operands, env);
}
if (operands->value.pair->first->type == Ast_Node_Type_Nil)
return create_ast_node_nil();
if (operands->value.pair->first->type != Ast_Node_Type_Pair)
report_error(Error_Type_Type_Missmatch);

return operands->value.pair->first->value.pair->rest;
} else if (string_equal("if", operator_name)) { } else if (string_equal("if", operator_name)) {
int operands_length = list_length(operands);
if (error) return nullptr;
try {
operands_length = list_length(operands);
}
if (operands_length != 2 && operands_length != 3) { if (operands_length != 2 && operands_length != 3) {
report_error(Error_Type_Wrong_Number_Of_Arguments); report_error(Error_Type_Wrong_Number_Of_Arguments);
} }
@@ -166,8 +279,10 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
Ast_Node* then_part = operands->value.pair->rest; Ast_Node* then_part = operands->value.pair->rest;
Ast_Node* else_part = then_part->value.pair->rest; Ast_Node* else_part = then_part->value.pair->rest;


bool truthy = is_truthy(condition, env);
if (error) return nullptr;
bool truthy;
try {
truthy = is_truthy(condition, env);
}
if (truthy) if (truthy)
return eval_expr(then_part->value.pair->first, env); return eval_expr(then_part->value.pair->first, env);
else if (operands_length == 3) else if (operands_length == 3)
@@ -180,8 +295,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
if (operands->type != Ast_Node_Type_Pair) { if (operands->type != Ast_Node_Type_Pair) {
report_error(Error_Type_Ill_Formed_List); report_error(Error_Type_Ill_Formed_List);
} }
result &= is_truthy(operands->value.pair->first, env);
if (error) return nullptr;
try {
result &= is_truthy(operands->value.pair->first, env);
}
operands = operands->value.pair->rest; operands = operands->value.pair->rest;


if (!result) return create_ast_node_nil(); if (!result) return create_ast_node_nil();
@@ -195,8 +311,9 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
if (operands->type != Ast_Node_Type_Pair) { if (operands->type != Ast_Node_Type_Pair) {
report_error(Error_Type_Ill_Formed_List); report_error(Error_Type_Ill_Formed_List);
} }
result |= is_truthy(operands->value.pair->first, env);
if (error) return nullptr;
try {
result |= is_truthy(operands->value.pair->first, env);
}
operands = operands->value.pair->rest; operands = operands->value.pair->rest;


if (result) return create_ast_node_number(1);; if (result) return create_ast_node_number(1);;
@@ -204,13 +321,16 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {


return create_ast_node_nil(); return create_ast_node_nil();
} else if (string_equal("not", operator_name)) { } else if (string_equal("not", operator_name)) {
if (list_length(operands) != 1) {
if (!error)
create_error(Error_Type_Wrong_Number_Of_Arguments, operands);
return nullptr;
try {
operands_length = list_length(operands);
}
if (operands_length != 1) {
report_error(Error_Type_Wrong_Number_Of_Arguments);
}
bool truthy;
try {
truthy = is_truthy(operands->value.pair->first, env);
} }
bool truthy = is_truthy(operands->value.pair->first, env);
if (error) return nullptr;
if (truthy) if (truthy)
return create_ast_node_nil(); return create_ast_node_nil();
return create_ast_node_number(1); return create_ast_node_number(1);


+ 15
- 1
src/helpers.c Просмотреть файл

@@ -1,6 +1,19 @@
#define new(type) (type*)malloc(sizeof(type)) #define new(type) (type*)malloc(sizeof(type))
#define nullptr NULL #define nullptr NULL


#define concat_( a, b) a##b
#define label(prefix, lnum) concat_(prefix,lnum)
#define try \
if (1) \
goto label(body,__LINE__); \
else \
while (1) \
if (1) { \
if(error) return 0; \
break; \
} \
else label(body,__LINE__):

typedef enum { false, true } bool; typedef enum { false, true } bool;


int string_equal(char* a, char* b) { int string_equal(char* a, char* b) {
@@ -75,7 +88,7 @@ char* read_entire_file (char* filename) {
} }


char* read_line() { char* read_line() {
char * line = malloc(100), * linep = line;
char* line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax; size_t lenmax = 100, len = lenmax;
int c; int c;


@@ -102,6 +115,7 @@ char* read_line() {
if((*line++ = c) == '\n') if((*line++ = c) == '\n')
break; break;
} }
*line--; // we dont want the \n actually
*line = '\0'; *line = '\0';
return linep; return linep;
} }

+ 4
- 3
src/parse.c Просмотреть файл

@@ -250,9 +250,10 @@ Ast_Node_Array_List* parse_program(char* text) {
while (text[index_in_text] != '\0') { while (text[index_in_text] != '\0') {
switch (text[index_in_text]) { switch (text[index_in_text]) {
case '(': { case '(': {
Ast_Node* parsed = parse_expression(text, &index_in_text);
if (error)
return nullptr;
Ast_Node* parsed;
try {
parsed = parse_expression(text, &index_in_text);
}
append_to_Ast_Node_Array_List(program, parsed); append_to_Ast_Node_Array_List(program, parsed);
} break; } break;
case ';': case ';':


+ 40
- 10
todo.org Просмотреть файл

@@ -31,25 +31,53 @@
#+RESULTS: #+RESULTS:
: t : t


** TODO first (car)
** TODO rest (cdr)
** TODO pair (cons)
** DONE first (car)
CLOSED: [2018-10-08 Mo 20:28]
** DONE rest (cdr)
CLOSED: [2018-10-08 Mo 20:28]
** DONE pair (cons)
CLOSED: [2018-10-08 Mo 20:28]


** TODO load (import) ** TODO load (import)
** TODO define
** DONE define
CLOSED: [2018-10-08 Mo 20:28]
** TODO lambda ** TODO lambda
** TODO progn ** TODO progn
** TODO eval
** TODO quote
** TODO print
** TODO read
** TODO help
** DONE eval
CLOSED: [2018-10-08 Mo 20:28]
** DONE quote
CLOSED: [2018-10-08 Mo 20:28]

** DONE list
CLOSED: [2018-10-08 Mo 21:06]

#+begin_src emacs-lisp
(quote (cons 2 (cons 3 (cons 4 ()))))
;; (cons 2 (cons 3 (cons 4 nil)))
(quote (2 . (3 . (4 . ()))))
;; (2 3 4)
#+end_src

#+begin_src emacs-lisp
(list (cons 2 (cons 3 (cons 4 ()))))
;; ((2 3 4))
(list (quote(2 . (3 . (4 . ())))))
#+end_src

** DONE print
CLOSED: [2018-10-08 Mo 20:28]
** DONE read
CLOSED: [2018-10-08 Mo 20:28]
** DONE type
CLOSED: [2018-10-08 Mo 21:30]

** TODO info


* Types * Types
- Symbol - Symbol
- Number - Number
- String - String
- Cons-cell (list)
- pair (cons-cell)
- lambda function lambda - lambda function lambda
- built-in function - built-in function


@@ -63,3 +91,5 @@
variable within an upper namespace it should variable within an upper namespace it should
infact change the environment even if the infact change the environment even if the
function exited function exited

(progn (setq x 4)(* x 2))

Загрузка…
Отмена
Сохранить