1
0
Fork 0

Add booleans

This commit is contained in:
Alex Kotov 2023-05-05 14:03:32 +04:00
parent 68b32c3799
commit 8581abcc0c
Signed by: kotovalexarian
GPG key ID: 553C0EBBEB5D5F08
9 changed files with 219 additions and 200 deletions

View file

@ -293,7 +293,7 @@ struct Object *func_display(struct Object *const args)
printf(")"); printf(")");
break; break;
case TYPE_BOOLEAN: case TYPE_BOOLEAN:
printf("%s", object->boolean ? "#t" : "#f"); printf("%s", object->boolean ? "#true" : "#false");
break; break;
case TYPE_CHAR: case TYPE_CHAR:
printf("#\\TODO"); // TODO printf("#\\TODO"); // TODO

View file

@ -2,7 +2,7 @@
#include <ctype.h> #include <ctype.h>
bool is_space(char chr) bool is_space(const char chr)
{ {
// ' ' (space) // ' ' (space)
// '\f' (form-feed) // '\f' (form-feed)
@ -13,7 +13,12 @@ bool is_space(char chr)
return isspace(chr); return isspace(chr);
} }
bool is_ident_head(char chr) bool is_tag(const char chr)
{
return isalnum(chr);
}
bool is_ident_head(const char chr)
{ {
return isalpha(chr) || return isalpha(chr) ||
chr == '!' || chr == '!' ||
@ -36,12 +41,12 @@ bool is_ident_head(char chr)
chr == '~'; chr == '~';
} }
bool is_ident_tail(char chr) bool is_ident_tail(const char chr)
{ {
return is_ident_head(chr) || isdigit(chr); return is_ident_head(chr) || isdigit(chr);
} }
bool is_number(char chr) bool is_number(const char chr)
{ {
return isdigit(chr); return isdigit(chr);
} }

View file

@ -4,6 +4,7 @@
#include <stdbool.h> #include <stdbool.h>
bool is_space(char chr); bool is_space(char chr);
bool is_tag(char chr);
bool is_ident_head(char chr); bool is_ident_head(char chr);
bool is_ident_tail(char chr); bool is_ident_tail(char chr);
bool is_number(char chr); bool is_number(char chr);

View file

@ -17,6 +17,8 @@ enum State {
STATE_CURLY_OPEN, STATE_CURLY_OPEN,
STATE_CURLY_CLOSE, STATE_CURLY_CLOSE,
STATE_QUOTE, STATE_QUOTE,
STATE_SHARP,
STATE_TAG,
STATE_IDENT, STATE_IDENT,
STATE_NUM, STATE_NUM,
}; };
@ -58,6 +60,7 @@ State_to_token_type(const enum State state, enum TokenType *const token_type)
case STATE_CURLY_CLOSE: *token_type = TOKEN_CURLY_CLOSE; break; case STATE_CURLY_CLOSE: *token_type = TOKEN_CURLY_CLOSE; break;
case STATE_QUOTE: *token_type = TOKEN_QUOTE; break; case STATE_QUOTE: *token_type = TOKEN_QUOTE; break;
case STATE_IDENT: *token_type = TOKEN_IDENT; break; case STATE_IDENT: *token_type = TOKEN_IDENT; break;
case STATE_TAG: *token_type = TOKEN_TAG; break;
case STATE_NUM: *token_type = TOKEN_NUM; break; case STATE_NUM: *token_type = TOKEN_NUM; break;
default: return false; default: return false;
} }
@ -112,6 +115,8 @@ void Lexer_lex(const Lexer self, const char chr)
} else if (chr == '\'') { } else if (chr == '\'') {
state = STATE_QUOTE; state = STATE_QUOTE;
buffer_add(chr); buffer_add(chr);
} else if (chr == '#') {
state = STATE_SHARP;
} else if (is_space(chr)) { } else if (is_space(chr)) {
state = STATE_WHITESPACE; state = STATE_WHITESPACE;
buffer_add(chr); buffer_add(chr);
@ -161,6 +166,10 @@ void Lexer_lex(const Lexer self, const char chr)
buffer_clean(); buffer_clean();
state = STATE_QUOTE; state = STATE_QUOTE;
buffer_add(chr); buffer_add(chr);
} else if (chr == '#') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_SHARP;
} else if (is_space(chr)) { } else if (is_space(chr)) {
buffer_add(chr); buffer_add(chr);
} else if (is_ident_head(chr)) { } else if (is_ident_head(chr)) {
@ -219,6 +228,10 @@ void Lexer_lex(const Lexer self, const char chr)
buffer_clean(); buffer_clean();
state = STATE_QUOTE; state = STATE_QUOTE;
buffer_add(chr); buffer_add(chr);
} else if (chr == '#') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_SHARP;
} else if (is_space(chr)) { } else if (is_space(chr)) {
token_add(self->tokens, state, buffer); token_add(self->tokens, state, buffer);
buffer_clean(); buffer_clean();
@ -238,6 +251,56 @@ void Lexer_lex(const Lexer self, const char chr)
abort(); abort();
} }
break; break;
case STATE_SHARP:
if (is_tag(chr)) {
state = STATE_TAG;
buffer_add(chr);
} else {
abort();
}
break;
case STATE_TAG:
if (chr == '(') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_ROUND_OPEN;
buffer_add(chr);
} else if (chr == ')') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_ROUND_CLOSE;
buffer_add(chr);
} else if (chr == '[') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_SQUARE_OPEN;
buffer_add(chr);
} else if (chr == ']') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_SQUARE_CLOSE;
buffer_add(chr);
} else if (chr == '{') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_CURLY_OPEN;
buffer_add(chr);
} else if (chr == '}') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_CURLY_CLOSE;
buffer_add(chr);
} else if (is_space(chr)) {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_WHITESPACE;
buffer_add(chr);
} else if (is_tag(chr)) {
buffer_add(chr);
} else {
abort();
}
break;
case STATE_IDENT: case STATE_IDENT:
if (chr == '(') { if (chr == '(') {
token_add(self->tokens, state, buffer); token_add(self->tokens, state, buffer);

View file

@ -260,8 +260,8 @@ void test()
struct Object *const sharp_true = Object_new_boolean(true); struct Object *const sharp_true = Object_new_boolean(true);
struct Object *const num_123 = Object_new_number(123); struct Object *const num_123 = Object_new_number(123);
// #t // #true
// #t // #true
assert(eval(sharp_true) == sharp_true); assert(eval(sharp_true) == sharp_true);
// 123 // 123
@ -276,8 +276,8 @@ void test()
) == sym_foo ) == sym_foo
); );
// (quote #t) // (quote #true)
// #t // #true
assert( assert(
eval( eval(
Object_build_list(2, Object_new_symbol("quote"), sharp_true) Object_build_list(2, Object_new_symbol("quote"), sharp_true)
@ -306,7 +306,7 @@ void test_if()
struct Object *const num_123 = Object_new_number(123); struct Object *const num_123 = Object_new_number(123);
struct Object *const num_456 = Object_new_number(456); struct Object *const num_456 = Object_new_number(456);
// (if #t 123 456) // (if #true 123 456)
assert(eval(Object_build_list( assert(eval(Object_build_list(
4, 4,
Object_new_symbol("if"), Object_new_symbol("if"),
@ -324,7 +324,7 @@ void test_if()
num_456 num_456
)) == num_123); )) == num_123);
// (if #f 123 456) // (if #false 123 456)
assert(eval(Object_build_list( assert(eval(Object_build_list(
4, 4,
Object_new_symbol("if"), Object_new_symbol("if"),
@ -419,31 +419,23 @@ void test_list()
void test_booleanQN() void test_booleanQN()
{ {
// (boolean? +) // (boolean? +)
// #f // #false
assert(Object_is_false(eval_str("(boolean? +)"))); assert(Object_is_false(eval_str("(boolean? +)")));
// (boolean? '()) // (boolean? '())
// #f // #false
assert(Object_is_false(eval_str("(boolean? '())"))); assert(Object_is_false(eval_str("(boolean? '())")));
// (boolean? #t) // (boolean? #true)
// #t // #true
assert(Object_is_true(eval(Object_build_list( assert(Object_is_true(eval_str("(boolean? #true)")));
2,
Object_new_symbol("boolean?"),
Object_new_boolean(true)
))));
// (boolean? #f) // (boolean? #false)
// #t // #true
assert(Object_is_true(eval(Object_build_list( assert(Object_is_true(eval_str("(boolean? #false)")));
2,
Object_new_symbol("boolean?"),
Object_new_boolean(false)
))));
// (boolean? #\n) // (boolean? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("boolean?"), Object_new_symbol("boolean?"),
@ -451,11 +443,11 @@ void test_booleanQN()
)))); ))));
// (boolean? 'foo) // (boolean? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(boolean? 'foo)"))); assert(Object_is_false(eval_str("(boolean? 'foo)")));
// (boolean? "foo") // (boolean? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("boolean?"), Object_new_symbol("boolean?"),
@ -463,42 +455,34 @@ void test_booleanQN()
)))); ))));
// (boolean? 123) // (boolean? 123)
// #f // #false
assert(Object_is_false(eval_str("(boolean? 123)"))); assert(Object_is_false(eval_str("(boolean? 123)")));
// (boolean? (cons 123 456)) // (boolean? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(boolean? (cons 123 456))"))); assert(Object_is_false(eval_str("(boolean? (cons 123 456))")));
} }
void test_charQN() void test_charQN()
{ {
// (char? +) // (char? +)
// #f // #false
assert(Object_is_false(eval_str("(char? +)"))); assert(Object_is_false(eval_str("(char? +)")));
// (char? '()) // (char? '())
// #f // #false
assert(Object_is_false(eval_str("(char? '())"))); assert(Object_is_false(eval_str("(char? '())")));
// (char? #t) // (char? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(char? #true)")));
2,
Object_new_symbol("char?"),
Object_new_boolean(true)
))));
// (char? #f) // (char? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(char? #false)")));
2,
Object_new_symbol("char?"),
Object_new_boolean(false)
))));
// (char? #\n) // (char? #\n)
// #t // #true
assert(Object_is_true(eval(Object_build_list( assert(Object_is_true(eval(Object_build_list(
2, 2,
Object_new_symbol("char?"), Object_new_symbol("char?"),
@ -506,11 +490,11 @@ void test_charQN()
)))); ))));
// (char? 'foo) // (char? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(char? 'foo)"))); assert(Object_is_false(eval_str("(char? 'foo)")));
// (char? "foo") // (char? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("char?"), Object_new_symbol("char?"),
@ -518,42 +502,34 @@ void test_charQN()
)))); ))));
// (char? 123) // (char? 123)
// #f // #false
assert(Object_is_false(eval_str("(char? 123)"))); assert(Object_is_false(eval_str("(char? 123)")));
// (char? (cons 123 456)) // (char? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(char? (cons 123 456))"))); assert(Object_is_false(eval_str("(char? (cons 123 456))")));
} }
void test_nullQN() void test_nullQN()
{ {
// (null? +) // (null? +)
// #f // #false
assert(Object_is_false(eval_str("(null? +)"))); assert(Object_is_false(eval_str("(null? +)")));
// (null? '()) // (null? '())
// #t // #true
assert(Object_is_true(eval_str("(null? '())"))); assert(Object_is_true(eval_str("(null? '())")));
// (null? #t) // (null? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(null? #true)")));
2,
Object_new_symbol("null?"),
Object_new_boolean(true)
))));
// (null? #f) // (null? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(null? #false)")));
2,
Object_new_symbol("null?"),
Object_new_boolean(false)
))));
// (null? #\n) // (null? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("null?"), Object_new_symbol("null?"),
@ -561,11 +537,11 @@ void test_nullQN()
)))); ))));
// (null? 'foo) // (null? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(null? 'foo)"))); assert(Object_is_false(eval_str("(null? 'foo)")));
// (null? "foo") // (null? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("null?"), Object_new_symbol("null?"),
@ -573,42 +549,34 @@ void test_nullQN()
)))); ))));
// (null? 123) // (null? 123)
// #f // #false
assert(Object_is_false(eval_str("(null? 123)"))); assert(Object_is_false(eval_str("(null? 123)")));
// (null? (cons 123 456)) // (null? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(null? (cons 123 456))"))); assert(Object_is_false(eval_str("(null? (cons 123 456))")));
} }
void test_numberQN() void test_numberQN()
{ {
// (number? +) // (number? +)
// #f // #false
assert(Object_is_false(eval_str("(number? +)"))); assert(Object_is_false(eval_str("(number? +)")));
// (number? '()) // (number? '())
// #f // #false
assert(Object_is_false(eval_str("(number? '())"))); assert(Object_is_false(eval_str("(number? '())")));
// (number? #t) // (number? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(number? #true)")));
2,
Object_new_symbol("number?"),
Object_new_boolean(true)
))));
// (number? #f) // (number? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(number? #false)")));
2,
Object_new_symbol("number?"),
Object_new_boolean(false)
))));
// (number? #\n) // (number? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("number?"), Object_new_symbol("number?"),
@ -616,11 +584,11 @@ void test_numberQN()
)))); ))));
// (number? 'foo) // (number? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(number? 'foo)"))); assert(Object_is_false(eval_str("(number? 'foo)")));
// (number? "foo") // (number? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("number?"), Object_new_symbol("number?"),
@ -628,42 +596,34 @@ void test_numberQN()
)))); ))));
// (number? 123) // (number? 123)
// #t // #true
assert(Object_is_true(eval_str("(number? 123)"))); assert(Object_is_true(eval_str("(number? 123)")));
// (number? (cons 123 456)) // (number? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(number? (cons 123 456))"))); assert(Object_is_false(eval_str("(number? (cons 123 456))")));
} }
void test_pairQN() void test_pairQN()
{ {
// (pair? +) // (pair? +)
// #f // #false
assert(Object_is_false(eval_str("(pair? +)"))); assert(Object_is_false(eval_str("(pair? +)")));
// (pair? '()) // (pair? '())
// #f // #false
assert(Object_is_false(eval_str("(pair? '())"))); assert(Object_is_false(eval_str("(pair? '())")));
// (pair? #t) // (pair? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(pair? #true)")));
2,
Object_new_symbol("pair?"),
Object_new_boolean(true)
))));
// (pair? #f) // (pair? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(pair? #false)")));
2,
Object_new_symbol("pair?"),
Object_new_boolean(false)
))));
// (pair? #\n) // (pair? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("pair?"), Object_new_symbol("pair?"),
@ -671,11 +631,11 @@ void test_pairQN()
)))); ))));
// (pair? 'foo) // (pair? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(pair? 'foo)"))); assert(Object_is_false(eval_str("(pair? 'foo)")));
// (pair? "foo") // (pair? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("pair?"), Object_new_symbol("pair?"),
@ -683,42 +643,34 @@ void test_pairQN()
)))); ))));
// (pair? 123) // (pair? 123)
// #f // #false
assert(Object_is_false(eval_str("(pair? 123)"))); assert(Object_is_false(eval_str("(pair? 123)")));
// (pair? (cons 123 456)) // (pair? (cons 123 456))
// #t // #true
assert(Object_is_true(eval_str("(pair? (cons 123 456))"))); assert(Object_is_true(eval_str("(pair? (cons 123 456))")));
} }
void test_procedureQN() void test_procedureQN()
{ {
// (procedure? +) // (procedure? +)
// #t // #true
assert(Object_is_true(eval_str("(procedure? +)"))); assert(Object_is_true(eval_str("(procedure? +)")));
// (procedure? '()) // (procedure? '())
// #f // #false
assert(Object_is_false(eval_str("(procedure? '())"))); assert(Object_is_false(eval_str("(procedure? '())")));
// (procedure? #t) // (procedure? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(procedure? #true)")));
2,
Object_new_symbol("procedure?"),
Object_new_boolean(true)
))));
// (procedure? #f) // (procedure? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(procedure? #false)")));
2,
Object_new_symbol("procedure?"),
Object_new_boolean(false)
))));
// (procedure? #\n) // (procedure? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("procedure?"), Object_new_symbol("procedure?"),
@ -726,11 +678,11 @@ void test_procedureQN()
)))); ))));
// (procedure? 'foo) // (procedure? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(procedure? 'foo)"))); assert(Object_is_false(eval_str("(procedure? 'foo)")));
// (procedure? "foo") // (procedure? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("procedure?"), Object_new_symbol("procedure?"),
@ -738,42 +690,34 @@ void test_procedureQN()
)))); ))));
// (procedure? 123) // (procedure? 123)
// #f // #false
assert(Object_is_false(eval_str("(procedure? 123)"))); assert(Object_is_false(eval_str("(procedure? 123)")));
// (procedure? (cons 123 456)) // (procedure? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(procedure? (cons 123 456))"))); assert(Object_is_false(eval_str("(procedure? (cons 123 456))")));
} }
void test_stringQN() void test_stringQN()
{ {
// (string? +) // (string? +)
// #f // #false
assert(Object_is_false(eval_str("(string? +)"))); assert(Object_is_false(eval_str("(string? +)")));
// (string? '()) // (string? '())
// #f // #false
assert(Object_is_false(eval_str("(string? '())"))); assert(Object_is_false(eval_str("(string? '())")));
// (string? #t) // (string? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(string? #true)")));
2,
Object_new_symbol("string?"),
Object_new_boolean(true)
))));
// (string? #f) // (string? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(string? #false)")));
2,
Object_new_symbol("string?"),
Object_new_boolean(false)
))));
// (string? #\n) // (string? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("string?"), Object_new_symbol("string?"),
@ -781,11 +725,11 @@ void test_stringQN()
)))); ))));
// (string? 'foo) // (string? 'foo)
// #f // #false
assert(Object_is_false(eval_str("(string? 'foo)"))); assert(Object_is_false(eval_str("(string? 'foo)")));
// (string? "foo") // (string? "foo")
// #t // #true
assert(Object_is_true(eval(Object_build_list( assert(Object_is_true(eval(Object_build_list(
2, 2,
Object_new_symbol("string?"), Object_new_symbol("string?"),
@ -793,42 +737,34 @@ void test_stringQN()
)))); ))));
// (string? 123) // (string? 123)
// #f // #false
assert(Object_is_false(eval_str("(string? 123)"))); assert(Object_is_false(eval_str("(string? 123)")));
// (string? (cons 123 456)) // (string? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(string? (cons 123 456))"))); assert(Object_is_false(eval_str("(string? (cons 123 456))")));
} }
void test_symbolQN() void test_symbolQN()
{ {
// (symbol? +) // (symbol? +)
// #f // #false
assert(Object_is_false(eval_str("(symbol? +)"))); assert(Object_is_false(eval_str("(symbol? +)")));
// (symbol? '()) // (symbol? '())
// #f // #false
assert(Object_is_false(eval_str("(symbol? '())"))); assert(Object_is_false(eval_str("(symbol? '())")));
// (symbol? #t) // (symbol? #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(symbol? #true)")));
2,
Object_new_symbol("symbol?"),
Object_new_boolean(true)
))));
// (symbol? #f) // (symbol? #false)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(symbol? #false)")));
2,
Object_new_symbol("symbol?"),
Object_new_boolean(false)
))));
// (symbol? #\n) // (symbol? #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("symbol?"), Object_new_symbol("symbol?"),
@ -836,11 +772,11 @@ void test_symbolQN()
)))); ))));
// (symbol? 'foo) // (symbol? 'foo)
// #t // #true
assert(Object_is_true(eval_str("(symbol? 'foo)"))); assert(Object_is_true(eval_str("(symbol? 'foo)")));
// (symbol? "foo") // (symbol? "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("symbol?"), Object_new_symbol("symbol?"),
@ -848,11 +784,11 @@ void test_symbolQN()
)))); ))));
// (symbol? 123) // (symbol? 123)
// #f // #false
assert(Object_is_false(eval_str("(symbol? 123)"))); assert(Object_is_false(eval_str("(symbol? 123)")));
// (symbol? (cons 123 456)) // (symbol? (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(symbol? (cons 123 456))"))); assert(Object_is_false(eval_str("(symbol? (cons 123 456))")));
} }
@ -887,30 +823,26 @@ void test_numberTOstring()
assert(strcmp(result->s, "1e240") == 0); assert(strcmp(result->s, "1e240") == 0);
} }
/*********************
* Logical operators *
*********************/
void test_not() void test_not()
{ {
// (not '()) // (not '())
// #f // #false
assert(Object_is_false(eval_str("(not '())"))); assert(Object_is_false(eval_str("(not '())")));
// (not #t) // (not #true)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval_str("(not #true)")));
2,
Object_new_symbol("not"),
Object_new_boolean(true)
))));
// (not #f) // (not #false)
// #t // #true
assert(Object_is_true(eval(Object_build_list( assert(Object_is_true(eval_str("(not #false)")));
2,
Object_new_symbol("not"),
Object_new_boolean(false)
))));
// (not #\n) // (not #\n)
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("not"), Object_new_symbol("not"),
@ -918,11 +850,11 @@ void test_not()
)))); ))));
// (not 'foo) // (not 'foo)
// #f // #false
assert(Object_is_false(eval_str("(not 'foo)"))); assert(Object_is_false(eval_str("(not 'foo)")));
// (not "foo") // (not "foo")
// #f // #false
assert(Object_is_false(eval(Object_build_list( assert(Object_is_false(eval(Object_build_list(
2, 2,
Object_new_symbol("not"), Object_new_symbol("not"),
@ -930,10 +862,10 @@ void test_not()
)))); ))));
// (not 123) // (not 123)
// #f // #false
assert(Object_is_false(eval_str("(not 123)"))); assert(Object_is_false(eval_str("(not 123)")));
// (not (cons 123 456)) // (not (cons 123 456))
// #f // #false
assert(Object_is_false(eval_str("(not (cons 123 456))"))); assert(Object_is_false(eval_str("(not (cons 123 456))")));
} }

View file

@ -190,7 +190,7 @@ void Object_print(struct Object *const self, const unsigned indent)
Object_print(self->pair.b, indent + 1); Object_print(self->pair.b, indent + 1);
break; break;
case TYPE_BOOLEAN: case TYPE_BOOLEAN:
printf("%s\n", self->boolean ? "#t" : "#f"); printf("%s\n", self->boolean ? "#true" : "#false");
break; break;
case TYPE_CHAR: case TYPE_CHAR:
printf("%c\n", self->chr); printf("%c\n", self->chr);

View file

@ -6,6 +6,7 @@
#include <assert.h> #include <assert.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
static void expect(Tokens tokens, enum TokenType token_type); static void expect(Tokens tokens, enum TokenType token_type);
@ -35,6 +36,21 @@ struct Object *expr(const Tokens tokens)
case TOKEN_QUOTE: case TOKEN_QUOTE:
Tokens_pop(tokens); Tokens_pop(tokens);
return Object_build_list(2, Object_new_symbol("quote"), expr(tokens)); return Object_build_list(2, Object_new_symbol("quote"), expr(tokens));
case TOKEN_TAG:
{
struct Object *object = NULL;
const char *const val = Tokens_top(tokens)->val;
assert(val);
if (strcmp(val, "f") == 0 || strcmp(val, "false") == 0) {
object = Object_new_boolean(false);
} else if (strcmp(val, "t") == 0 || strcmp(val, "true") == 0) {
object = Object_new_boolean(true);
} else {
assert(0);
}
Tokens_pop(tokens);
return object;
}
case TOKEN_IDENT: case TOKEN_IDENT:
{ {
struct Object *const object = Object_new_symbol(Tokens_top(tokens)->val); struct Object *const object = Object_new_symbol(Tokens_top(tokens)->val);

View file

@ -16,6 +16,7 @@ const char *TokenType_to_str(const enum TokenType token_type)
case TOKEN_CURLY_OPEN: return "TOKEN_CURLY_OPEN"; case TOKEN_CURLY_OPEN: return "TOKEN_CURLY_OPEN";
case TOKEN_CURLY_CLOSE: return "TOKEN_CURLY_CLOSE"; case TOKEN_CURLY_CLOSE: return "TOKEN_CURLY_CLOSE";
case TOKEN_QUOTE: return "TOKEN_QUOTE"; case TOKEN_QUOTE: return "TOKEN_QUOTE";
case TOKEN_TAG: return "TOKEN_TAG";
case TOKEN_IDENT: return "TOKEN_IDENT"; case TOKEN_IDENT: return "TOKEN_IDENT";
case TOKEN_NUM: return "TOKEN_NUM"; case TOKEN_NUM: return "TOKEN_NUM";
} }

View file

@ -17,6 +17,7 @@ enum TokenType {
TOKEN_CURLY_OPEN, TOKEN_CURLY_OPEN,
TOKEN_CURLY_CLOSE, TOKEN_CURLY_CLOSE,
TOKEN_QUOTE, TOKEN_QUOTE,
TOKEN_TAG,
TOKEN_IDENT, TOKEN_IDENT,
TOKEN_NUM, TOKEN_NUM,
}; };