diff --git a/.gitignore b/.gitignore index 9bea739..7328693 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /arcane-scheme-lisp /arcane-scheme-lisp-test + +/test.out diff --git a/Makefile b/Makefile index baf3aa6..cefa98d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,16 @@ all: test +CAT = cat CC = gcc +DIFF_Q = diff -q +RM_F = rm -f + CFLAGS = -Wall -Wextra +TEST_SCM = test.scm +TEST_EXP = test.txt +TEST_OUT = test.out + OBJS = \ src/builtins.c.o \ src/ctype.c.o \ @@ -21,9 +29,11 @@ repl: arcane-scheme-lisp test: arcane-scheme-lisp arcane-scheme-lisp-test ./arcane-scheme-lisp-test + $(CAT) $(TEST_SCM) | ./arcane-scheme-lisp > $(TEST_OUT) + $(DIFF_Q) $(TEST_EXP) $(TEST_OUT) clean: - rm -f arcane-scheme-lisp arcane-scheme-lisp-test $(MAIN_OBJS) $(TEST_OBJS) + $(RM_F) arcane-scheme-lisp arcane-scheme-lisp-test $(MAIN_OBJS) $(TEST_OBJS) $(TEST_OUT) arcane-scheme-lisp: $(MAIN_OBJS) $(CC) -o $@ $^ $(CFLAGS) diff --git a/src/lexer.c b/src/lexer.c index bbfc212..459b32b 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -4,6 +4,7 @@ #include "tokens.h" #include +#include #include #include @@ -87,6 +88,7 @@ void token_add(const Lexer lexer) void Lexer_lex(const Lexer self, const char chr) { assert(self); + assert(chr != EOF); switch (self->state) { case STATE_INIT: diff --git a/src/main.c b/src/main.c index 79be97e..df523c1 100644 --- a/src/main.c +++ b/src/main.c @@ -10,32 +10,39 @@ #include #include #include +#include int main() { - while (true) { + const bool is_tty = isatty(fileno(stdin)); + + do { Tokens tokens = Tokens_new(); assert(tokens); Lexer lexer = Lexer_new(tokens); assert(lexer); - printf(">> "); + if (is_tty) printf(">> "); + while (true) { const char chr = getchar(); - if (chr == EOF) { - putchar('\n'); - exit(EXIT_SUCCESS); + + if (is_tty) { + if (chr == EOF) { + putchar('\n'); + exit(EXIT_SUCCESS); + } + + if (chr == '\n') break; } - if (chr == '\n') { - Lexer_lex(lexer, '\n'); - break; - } + if (chr == EOF) break; Lexer_lex(lexer, chr); } + Lexer_lex(lexer, '\n'); LEXER_DELETE(lexer); if (Tokens_top(tokens) == NULL) continue; @@ -44,13 +51,15 @@ int main() struct Object *const result = eval(program); - printf("=> "); - eval(Object_build_list( - 2, - Object_new_symbol("displayln"), - Object_build_list(2, Object_new_symbol("quote"), result) - )); - } + if (is_tty) { + printf("=> "); + eval(Object_build_list( + 2, + Object_new_symbol("displayln"), + Object_build_list(2, Object_new_symbol("quote"), result) + )); + } + } while (is_tty); exit(EXIT_SUCCESS); } diff --git a/test.scm b/test.scm new file mode 100644 index 0000000..f274924 --- /dev/null +++ b/test.scm @@ -0,0 +1,196 @@ +(begin + (displayln "Hello, World!") + (newline) + (displayln "=== GROUP: Syntax ==============================================") + (newline) + (displayln "--- TEST: begin ------------------------------------------------") + (displayln (begin)) + (displayln (begin 123)) + (displayln (begin 123 456)) + (displayln (begin 123 456 789)) + (newline) + (displayln "--- TEST: if ---------------------------------------------------") + (displayln (if #true 123 456)) + (displayln (if "foo" 123 456)) + (displayln (if #false 123 456)) + (newline) + (displayln "=== GROUP: Arcane Scheme Lisp internals ========================") + (newline) + (displayln "--- TEST: arcane/tokenize --------------------------------------") + (displayln (arcane/tokenize "(")) + (displayln (arcane/tokenize "#false")) + '(displayln (arcane/tokenize "''")) + '(displayln (arcane/tokenize "'qwe'")) + (displayln (arcane/tokenize "(displayln (list 1))")) + (newline) + (displayln "--- TEST: arcane/typeof ----------------------------------------") + (displayln (arcane/typeof '())) + (displayln (arcane/typeof +)) + (displayln (arcane/typeof (cons 123 456))) + (displayln (arcane/typeof #false)) + '(displayln (arcane/typeof "#\n")) + (displayln (arcane/typeof 'foo)) + (displayln (arcane/typeof "foo")) + (displayln (arcane/typeof 123)) + (newline) + (displayln "=== GROUP: Basic data structures ===============================") + (newline) + (displayln "--- TEST: car --------------------------------------------------") + (displayln (car (cons 123 456))) + (newline) + (displayln "--- TEST: cdr --------------------------------------------------") + (displayln (cdr (cons 123 456))) + (newline) + (displayln "--- TEST: list -------------------------------------------------") + (displayln (list)) + (displayln (list 123)) + (displayln (list 123 456)) + (newline) + (displayln "=== GROUP: Type predicates =====================================") + (newline) + (displayln "--- TEST: boolean? ---------------------------------------------") + (displayln (boolean? +)) + (displayln (boolean? '())) + (displayln (boolean? #true)) + (displayln (boolean? #false)) + '(displayln (boolean? "#\n")) + (displayln (boolean? 'foo)) + (displayln (boolean? "foo")) + (displayln (boolean? 123)) + (displayln (boolean? (cons 123 456))) + (newline) + (displayln "--- TEST: char? ------------------------------------------------") + (displayln (char? +)) + (displayln (char? '())) + (displayln (char? #true)) + (displayln (char? #false)) + '(displayln (char? "#\n")) + (displayln (char? 'foo)) + (displayln (char? "foo")) + (displayln (char? 123)) + (displayln (char? (cons 123 456))) + (newline) + (displayln "--- TEST: null? ------------------------------------------------") + (displayln (null? +)) + (displayln (null? '())) + (displayln (null? #true)) + (displayln (null? #false)) + '(displayln (null? "#\n")) + (displayln (null? 'foo)) + (displayln (null? "foo")) + (displayln (null? 123)) + (displayln (null? (cons 123 456))) + (newline) + (displayln "--- TEST: number? ----------------------------------------------") + (displayln (number? +)) + (displayln (number? '())) + (displayln (number? #true)) + (displayln (number? #false)) + '(displayln (number? "#\n")) + (displayln (number? 'foo)) + (displayln (number? "foo")) + (displayln (number? 123)) + (displayln (number? (cons 123 456))) + (newline) + (displayln "--- TEST: pair? ------------------------------------------------") + (displayln (pair? +)) + (displayln (pair? '())) + (displayln (pair? #true)) + (displayln (pair? #false)) + '(displayln (pair? "#\n")) + (displayln (pair? 'foo)) + (displayln (pair? "foo")) + (displayln (pair? 123)) + (displayln (pair? (cons 123 456))) + (newline) + (displayln "--- TEST: procedure? -------------------------------------------") + (displayln (procedure? +)) + (displayln (procedure? '())) + (displayln (procedure? #true)) + (displayln (procedure? #false)) + '(displayln (procedure? "#\n")) + (displayln (procedure? 'foo)) + (displayln (procedure? "foo")) + (displayln (procedure? 123)) + (displayln (procedure? (cons 123 456))) + (newline) + (displayln "--- TEST: string? ----------------------------------------------") + (displayln (string? +)) + (displayln (string? '())) + (displayln (string? #true)) + (displayln (string? #false)) + '(displayln (string? "#\n")) + (displayln (string? 'foo)) + (displayln (string? "foo")) + (displayln (string? 123)) + (displayln (string? (cons 123 456))) + (newline) + (displayln "--- TEST: symbol? ----------------------------------------------") + (displayln (symbol? +)) + (displayln (symbol? '())) + (displayln (symbol? #true)) + (displayln (symbol? #false)) + '(displayln (symbol? "#\n")) + (displayln (symbol? 'foo)) + (displayln (symbol? "foo")) + (displayln (symbol? 123)) + (displayln (symbol? (cons 123 456))) + (newline) + (displayln "=== GROUP: Type conversion =====================================") + (newline) + (displayln "--- TEST: number->string ---------------------------------------") + (displayln (number->string 123)) + '(displayln (number->string "-123")) + (displayln (number->string 123456 16)) + (newline) + (displayln "--- TEST: string->symbol ---------------------------------------") + (displayln (string->symbol "")) + (displayln (string->symbol " ")) + (displayln (string->symbol "foo")) + (newline) + (displayln "--- TEST: symbol->string ---------------------------------------") + (displayln (symbol->string 'foo)) + (newline) + (displayln "=== GROUP: Logical operators ===================================") + (newline) + (displayln "--- TEST: not --------------------------------------------------") + (displayln (not '())) + (displayln (not #true)) + (displayln (not #false)) + '(displayln (not "#\n")) + (displayln (not 'foo)) + (displayln (not "foo")) + (displayln (not 123)) + (displayln (not (cons 123 456))) + (newline) + (displayln "=== GROUP: Arithmetic operators ================================") + (newline) + (displayln "--- TEST: = ----------------------------------------------------") + (displayln(= 123)) + (displayln(= 123 123)) + (displayln(= 123 456)) + (displayln(= 123 123 123)) + (displayln(= 456 123 123)) + (displayln(= 123 456 123)) + (displayln(= 123 123 456)) + (displayln(= 123 123 123 123)) + (displayln(= 456 123 123 123)) + (displayln(= 123 456 123 123)) + (displayln(= 123 123 456 123)) + (displayln(= 123 123 123 456)) + (newline) + (displayln "--- TEST: + ----------------------------------------------------") + (displayln (+)) + (displayln (+ 123)) + (displayln (+ 1 10)) + (displayln (+ 1 10 100)) + (displayln (+ 1 10 100 1000)) + (newline) + (displayln "--- TEST: - ----------------------------------------------------") + (displayln (- 0)) + (displayln (- 123)) + (displayln (- 100 1)) + (displayln (- 100 1 2)) + (displayln (- 100 1 2 3)) + (displayln (- 100 1 2 3 4)) +) diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..38457ab --- /dev/null +++ b/test.txt @@ -0,0 +1,181 @@ +"Hello, World!" + +"=== GROUP: Syntax ==============================================" + +"--- TEST: begin ------------------------------------------------" +() +123 +456 +789 + +"--- TEST: if ---------------------------------------------------" +123 +123 +456 + +"=== GROUP: Arcane Scheme Lisp internals ========================" + +"--- TEST: arcane/tokenize --------------------------------------" +((TOKEN_ROUND_OPEN . "(")) +((TOKEN_TAG . "false")) +((TOKEN_ROUND_OPEN . "(") (TOKEN_IDENT . "displayln") (TOKEN_ROUND_OPEN . "(") (TOKEN_IDENT . "list") (TOKEN_NUM . "1") (TOKEN_ROUND_CLOSE . ")") (TOKEN_ROUND_CLOSE . ")")) + +"--- TEST: arcane/typeof ----------------------------------------" +null +procedure +pair +boolean +symbol +string +number + +"=== GROUP: Basic data structures ===============================" + +"--- TEST: car --------------------------------------------------" +123 + +"--- TEST: cdr --------------------------------------------------" +456 + +"--- TEST: list -------------------------------------------------" +() +(123) +(123 456) + +"=== GROUP: Type predicates =====================================" + +"--- TEST: boolean? ---------------------------------------------" +#false +#false +#true +#true +#false +#false +#false +#false + +"--- TEST: char? ------------------------------------------------" +#false +#false +#false +#false +#false +#false +#false +#false + +"--- TEST: null? ------------------------------------------------" +#false +#true +#false +#false +#false +#false +#false +#false + +"--- TEST: number? ----------------------------------------------" +#false +#false +#false +#false +#false +#false +#true +#false + +"--- TEST: pair? ------------------------------------------------" +#false +#false +#false +#false +#false +#false +#false +#true + +"--- TEST: procedure? -------------------------------------------" +#true +#false +#false +#false +#false +#false +#false +#false + +"--- TEST: string? ----------------------------------------------" +#false +#false +#false +#false +#false +#true +#false +#false + +"--- TEST: symbol? ----------------------------------------------" +#false +#false +#false +#false +#true +#false +#false +#false + +"=== GROUP: Type conversion =====================================" + +"--- TEST: number->string ---------------------------------------" +"123" +"1e240" + +"--- TEST: string->symbol ---------------------------------------" + + +foo + +"--- TEST: symbol->string ---------------------------------------" +"foo" + +"=== GROUP: Logical operators ===================================" + +"--- TEST: not --------------------------------------------------" +#false +#false +#true +#false +#false +#false +#false + +"=== GROUP: Arithmetic operators ================================" + +"--- TEST: = ----------------------------------------------------" +#true +#true +#false +#true +#false +#false +#false +#true +#false +#false +#false +#false + +"--- TEST: + ----------------------------------------------------" +0 +123 +11 +111 +1111 + +"--- TEST: - ----------------------------------------------------" +0 +123 +99 +97 +94 +90