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(")");
break;
case TYPE_BOOLEAN:
printf("%s", object->boolean ? "#t" : "#f");
printf("%s", object->boolean ? "#true" : "#false");
break;
case TYPE_CHAR:
printf("#\\TODO"); // TODO

View file

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

View file

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

View file

@ -17,6 +17,8 @@ enum State {
STATE_CURLY_OPEN,
STATE_CURLY_CLOSE,
STATE_QUOTE,
STATE_SHARP,
STATE_TAG,
STATE_IDENT,
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_QUOTE: *token_type = TOKEN_QUOTE; 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;
default: return false;
}
@ -112,6 +115,8 @@ void Lexer_lex(const Lexer self, const char chr)
} else if (chr == '\'') {
state = STATE_QUOTE;
buffer_add(chr);
} else if (chr == '#') {
state = STATE_SHARP;
} else if (is_space(chr)) {
state = STATE_WHITESPACE;
buffer_add(chr);
@ -161,6 +166,10 @@ void Lexer_lex(const Lexer self, const char chr)
buffer_clean();
state = STATE_QUOTE;
buffer_add(chr);
} else if (chr == '#') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_SHARP;
} else if (is_space(chr)) {
buffer_add(chr);
} else if (is_ident_head(chr)) {
@ -219,6 +228,10 @@ void Lexer_lex(const Lexer self, const char chr)
buffer_clean();
state = STATE_QUOTE;
buffer_add(chr);
} else if (chr == '#') {
token_add(self->tokens, state, buffer);
buffer_clean();
state = STATE_SHARP;
} else if (is_space(chr)) {
token_add(self->tokens, state, buffer);
buffer_clean();
@ -238,6 +251,56 @@ void Lexer_lex(const Lexer self, const char chr)
abort();
}
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:
if (chr == '(') {
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 num_123 = Object_new_number(123);
// #t
// #t
// #true
// #true
assert(eval(sharp_true) == sharp_true);
// 123
@ -276,8 +276,8 @@ void test()
) == sym_foo
);
// (quote #t)
// #t
// (quote #true)
// #true
assert(
eval(
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_456 = Object_new_number(456);
// (if #t 123 456)
// (if #true 123 456)
assert(eval(Object_build_list(
4,
Object_new_symbol("if"),
@ -324,7 +324,7 @@ void test_if()
num_456
)) == num_123);
// (if #f 123 456)
// (if #false 123 456)
assert(eval(Object_build_list(
4,
Object_new_symbol("if"),
@ -419,31 +419,23 @@ void test_list()
void test_booleanQN()
{
// (boolean? +)
// #f
// #false
assert(Object_is_false(eval_str("(boolean? +)")));
// (boolean? '())
// #f
// #false
assert(Object_is_false(eval_str("(boolean? '())")));
// (boolean? #t)
// #t
assert(Object_is_true(eval(Object_build_list(
2,
Object_new_symbol("boolean?"),
Object_new_boolean(true)
))));
// (boolean? #true)
// #true
assert(Object_is_true(eval_str("(boolean? #true)")));
// (boolean? #f)
// #t
assert(Object_is_true(eval(Object_build_list(
2,
Object_new_symbol("boolean?"),
Object_new_boolean(false)
))));
// (boolean? #false)
// #true
assert(Object_is_true(eval_str("(boolean? #false)")));
// (boolean? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("boolean?"),
@ -451,11 +443,11 @@ void test_booleanQN()
))));
// (boolean? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(boolean? 'foo)")));
// (boolean? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("boolean?"),
@ -463,42 +455,34 @@ void test_booleanQN()
))));
// (boolean? 123)
// #f
// #false
assert(Object_is_false(eval_str("(boolean? 123)")));
// (boolean? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(boolean? (cons 123 456))")));
}
void test_charQN()
{
// (char? +)
// #f
// #false
assert(Object_is_false(eval_str("(char? +)")));
// (char? '())
// #f
// #false
assert(Object_is_false(eval_str("(char? '())")));
// (char? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("char?"),
Object_new_boolean(true)
))));
// (char? #true)
// #false
assert(Object_is_false(eval_str("(char? #true)")));
// (char? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("char?"),
Object_new_boolean(false)
))));
// (char? #false)
// #false
assert(Object_is_false(eval_str("(char? #false)")));
// (char? #\n)
// #t
// #true
assert(Object_is_true(eval(Object_build_list(
2,
Object_new_symbol("char?"),
@ -506,11 +490,11 @@ void test_charQN()
))));
// (char? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(char? 'foo)")));
// (char? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("char?"),
@ -518,42 +502,34 @@ void test_charQN()
))));
// (char? 123)
// #f
// #false
assert(Object_is_false(eval_str("(char? 123)")));
// (char? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(char? (cons 123 456))")));
}
void test_nullQN()
{
// (null? +)
// #f
// #false
assert(Object_is_false(eval_str("(null? +)")));
// (null? '())
// #t
// #true
assert(Object_is_true(eval_str("(null? '())")));
// (null? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("null?"),
Object_new_boolean(true)
))));
// (null? #true)
// #false
assert(Object_is_false(eval_str("(null? #true)")));
// (null? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("null?"),
Object_new_boolean(false)
))));
// (null? #false)
// #false
assert(Object_is_false(eval_str("(null? #false)")));
// (null? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("null?"),
@ -561,11 +537,11 @@ void test_nullQN()
))));
// (null? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(null? 'foo)")));
// (null? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("null?"),
@ -573,42 +549,34 @@ void test_nullQN()
))));
// (null? 123)
// #f
// #false
assert(Object_is_false(eval_str("(null? 123)")));
// (null? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(null? (cons 123 456))")));
}
void test_numberQN()
{
// (number? +)
// #f
// #false
assert(Object_is_false(eval_str("(number? +)")));
// (number? '())
// #f
// #false
assert(Object_is_false(eval_str("(number? '())")));
// (number? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("number?"),
Object_new_boolean(true)
))));
// (number? #true)
// #false
assert(Object_is_false(eval_str("(number? #true)")));
// (number? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("number?"),
Object_new_boolean(false)
))));
// (number? #false)
// #false
assert(Object_is_false(eval_str("(number? #false)")));
// (number? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("number?"),
@ -616,11 +584,11 @@ void test_numberQN()
))));
// (number? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(number? 'foo)")));
// (number? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("number?"),
@ -628,42 +596,34 @@ void test_numberQN()
))));
// (number? 123)
// #t
// #true
assert(Object_is_true(eval_str("(number? 123)")));
// (number? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(number? (cons 123 456))")));
}
void test_pairQN()
{
// (pair? +)
// #f
// #false
assert(Object_is_false(eval_str("(pair? +)")));
// (pair? '())
// #f
// #false
assert(Object_is_false(eval_str("(pair? '())")));
// (pair? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("pair?"),
Object_new_boolean(true)
))));
// (pair? #true)
// #false
assert(Object_is_false(eval_str("(pair? #true)")));
// (pair? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("pair?"),
Object_new_boolean(false)
))));
// (pair? #false)
// #false
assert(Object_is_false(eval_str("(pair? #false)")));
// (pair? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("pair?"),
@ -671,11 +631,11 @@ void test_pairQN()
))));
// (pair? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(pair? 'foo)")));
// (pair? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("pair?"),
@ -683,42 +643,34 @@ void test_pairQN()
))));
// (pair? 123)
// #f
// #false
assert(Object_is_false(eval_str("(pair? 123)")));
// (pair? (cons 123 456))
// #t
// #true
assert(Object_is_true(eval_str("(pair? (cons 123 456))")));
}
void test_procedureQN()
{
// (procedure? +)
// #t
// #true
assert(Object_is_true(eval_str("(procedure? +)")));
// (procedure? '())
// #f
// #false
assert(Object_is_false(eval_str("(procedure? '())")));
// (procedure? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("procedure?"),
Object_new_boolean(true)
))));
// (procedure? #true)
// #false
assert(Object_is_false(eval_str("(procedure? #true)")));
// (procedure? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("procedure?"),
Object_new_boolean(false)
))));
// (procedure? #false)
// #false
assert(Object_is_false(eval_str("(procedure? #false)")));
// (procedure? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("procedure?"),
@ -726,11 +678,11 @@ void test_procedureQN()
))));
// (procedure? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(procedure? 'foo)")));
// (procedure? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("procedure?"),
@ -738,42 +690,34 @@ void test_procedureQN()
))));
// (procedure? 123)
// #f
// #false
assert(Object_is_false(eval_str("(procedure? 123)")));
// (procedure? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(procedure? (cons 123 456))")));
}
void test_stringQN()
{
// (string? +)
// #f
// #false
assert(Object_is_false(eval_str("(string? +)")));
// (string? '())
// #f
// #false
assert(Object_is_false(eval_str("(string? '())")));
// (string? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("string?"),
Object_new_boolean(true)
))));
// (string? #true)
// #false
assert(Object_is_false(eval_str("(string? #true)")));
// (string? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("string?"),
Object_new_boolean(false)
))));
// (string? #false)
// #false
assert(Object_is_false(eval_str("(string? #false)")));
// (string? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("string?"),
@ -781,11 +725,11 @@ void test_stringQN()
))));
// (string? 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(string? 'foo)")));
// (string? "foo")
// #t
// #true
assert(Object_is_true(eval(Object_build_list(
2,
Object_new_symbol("string?"),
@ -793,42 +737,34 @@ void test_stringQN()
))));
// (string? 123)
// #f
// #false
assert(Object_is_false(eval_str("(string? 123)")));
// (string? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(string? (cons 123 456))")));
}
void test_symbolQN()
{
// (symbol? +)
// #f
// #false
assert(Object_is_false(eval_str("(symbol? +)")));
// (symbol? '())
// #f
// #false
assert(Object_is_false(eval_str("(symbol? '())")));
// (symbol? #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("symbol?"),
Object_new_boolean(true)
))));
// (symbol? #true)
// #false
assert(Object_is_false(eval_str("(symbol? #true)")));
// (symbol? #f)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("symbol?"),
Object_new_boolean(false)
))));
// (symbol? #false)
// #false
assert(Object_is_false(eval_str("(symbol? #false)")));
// (symbol? #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("symbol?"),
@ -836,11 +772,11 @@ void test_symbolQN()
))));
// (symbol? 'foo)
// #t
// #true
assert(Object_is_true(eval_str("(symbol? 'foo)")));
// (symbol? "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("symbol?"),
@ -848,11 +784,11 @@ void test_symbolQN()
))));
// (symbol? 123)
// #f
// #false
assert(Object_is_false(eval_str("(symbol? 123)")));
// (symbol? (cons 123 456))
// #f
// #false
assert(Object_is_false(eval_str("(symbol? (cons 123 456))")));
}
@ -887,30 +823,26 @@ void test_numberTOstring()
assert(strcmp(result->s, "1e240") == 0);
}
/*********************
* Logical operators *
*********************/
void test_not()
{
// (not '())
// #f
// #false
assert(Object_is_false(eval_str("(not '())")));
// (not #t)
// #f
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("not"),
Object_new_boolean(true)
))));
// (not #true)
// #false
assert(Object_is_false(eval_str("(not #true)")));
// (not #f)
// #t
assert(Object_is_true(eval(Object_build_list(
2,
Object_new_symbol("not"),
Object_new_boolean(false)
))));
// (not #false)
// #true
assert(Object_is_true(eval_str("(not #false)")));
// (not #\n)
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("not"),
@ -918,11 +850,11 @@ void test_not()
))));
// (not 'foo)
// #f
// #false
assert(Object_is_false(eval_str("(not 'foo)")));
// (not "foo")
// #f
// #false
assert(Object_is_false(eval(Object_build_list(
2,
Object_new_symbol("not"),
@ -930,10 +862,10 @@ void test_not()
))));
// (not 123)
// #f
// #false
assert(Object_is_false(eval_str("(not 123)")));
// (not (cons 123 456))
// #f
// #false
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);
break;
case TYPE_BOOLEAN:
printf("%s\n", self->boolean ? "#t" : "#f");
printf("%s\n", self->boolean ? "#true" : "#false");
break;
case TYPE_CHAR:
printf("%c\n", self->chr);

View file

@ -6,6 +6,7 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
static void expect(Tokens tokens, enum TokenType token_type);
@ -35,6 +36,21 @@ struct Object *expr(const Tokens tokens)
case TOKEN_QUOTE:
Tokens_pop(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:
{
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_CLOSE: return "TOKEN_CURLY_CLOSE";
case TOKEN_QUOTE: return "TOKEN_QUOTE";
case TOKEN_TAG: return "TOKEN_TAG";
case TOKEN_IDENT: return "TOKEN_IDENT";
case TOKEN_NUM: return "TOKEN_NUM";
}

View file

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