Mercurial > lbo > hg > ylisp
view src/built-ins_test.c @ 164:f91caf9fe066
built-ins: Test `print` built-in
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 03 Sep 2019 17:17:02 +0200 |
parents | fe5d01fa28ee |
children | 97e8d35ede6d |
line wrap: on
line source
#include "built-ins.h" #define _POSIX_C_SOURCE 200809 #include <stdio.h> #include "atom.h" #include "parse.h" #include "preprocess.h" #include "value.h" void test_builtin_translate(void) { fprintf(stderr, "test_builtin_translate ============\n"); yexpr_t expr = yexpr_new(); yexpr_set_atom(&expr, yatom_get_or_add("atom")); assert(!ybuiltin_translate(&expr)); assert(YEXPR_ATOM == expr.typ); yexpr_set_ref(&expr, yref_new()); assert(!ybuiltin_translate(&expr)); assert(YEXPR_REF == expr.typ); yexpr_set_ref(&expr, yref_new_c("my-ref")); assert(!ybuiltin_translate(&expr)); assert(YEXPR_REF == expr.typ); yexpr_destroy(&expr); yexpr_set_ref(&expr, yref_new_c("let")); assert(ybuiltin_translate(&expr)); assert(YEXPR_BUILTIN == expr.typ); assert(YBUILTIN_LET == expr.value.builtin); } void test_builtin_for(void) { fprintf(stderr, "test_builtin_for ============\n"); ystr_t input = ystr_new("(for loopvar (1 2 3) loopvar)"), error = ystr_new(NULL); yexpr_t program = yexpr_new(); assert(yparse_str(&input, &program, &error)); yexpr_t* for_expr = YVEC_AT(&program.value.list, 0, yexpr_t); assert(for_expr->typ == YEXPR_LIST); yexpr_debug(&program); ypreprocess_resolve_builtins(&program); ypreprocess_refs(&program); yexpr_debug(&program); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; YVEC_PUSH(&state.call_stack, for_expr); yexpr_t result = ybuiltin_run(YBUILTIN_FOR, &state); assert(result.typ == YEXPR_LIST); yexpr_debug(&result); yvec_destroy(&state.call_stack); yexpr_destroy(&program); yexpr_destroy(&result); ystr_destroy(&input); } void test_builtin_for_complex(void) { fprintf(stderr, "test_builtin_for_complex ============\n"); ystr_t input = ystr_new("(for loopvar (1 2 3) (+ loopvar 1 2))"), error = ystr_new(NULL); yexpr_t program = yexpr_new(); assert(yparse_str(&input, &program, &error)); yexpr_t* for_expr = YVEC_AT(&program.value.list, 0, yexpr_t); assert(for_expr->typ == YEXPR_LIST); ypreprocess(&program); yexpr_debug(for_expr); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; YVEC_PUSH(&state.call_stack, for_expr); yexpr_t result = ybuiltin_run(YBUILTIN_FOR, &state); assert(result.typ == YEXPR_LIST); // (1 2 3) should each be increased by 3. yexpr_debug(&result); assert(4 == YVEC_AT(&result.value.list, 0, yexpr_t)->value.n); yvec_destroy(&state.call_stack); yexpr_destroy(&program); yexpr_destroy(&result); ystr_destroy(&input); } void test_builtin_for_noresult(void) { fprintf(stderr, "test_builtin_for_noresult ============\n"); ystr_t input = ystr_new("(for loopvar (1 2 3) (undef))"), error = ystr_new(NULL); yexpr_t program = yexpr_new(); assert(yparse_str(&input, &program, &error)); yexpr_t* for_expr = YVEC_AT(&program.value.list, 0, yexpr_t); assert(for_expr->typ == YEXPR_LIST); ypreprocess_resolve_builtins(&program); ypreprocess_refs(&program); yexpr_debug(for_expr); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; YVEC_PUSH(&state.call_stack, for_expr); yexpr_t result = ybuiltin_run(YBUILTIN_FOR, &state); assert(result.typ == YEXPR_LIST); assert(result.value.list.len == 0); yvec_destroy(&state.call_stack); yexpr_destroy(&program); ystr_destroy(&input); yexpr_destroy(&result); } void test_builtin_let(void) { fprintf(stderr, "test_builtin_let ============\n"); yexpr_t ref_expr = yexpr_new(); yexpr_t let_expr = yexpr_new(); yref_t ref = yref_new(); yexpr_t val_expr = yexpr_new(); yexpr_t let_call = yexpr_new(); // (let <ref> 'my-atom) yexpr_set_ref(&ref_expr, ref); yexpr_set_builtin(&let_expr, YBUILTIN_LET); yexpr_set_atom(&val_expr, yatom_get_or_add("my-atom")); yvec_t let_args; YVEC_INIT(&let_args, 4, yexpr_t); YVEC_PUSH(&let_args, &let_expr); YVEC_PUSH(&let_args, &ref_expr); YVEC_PUSH(&let_args, &val_expr); yexpr_set_list(&let_call, let_args); // NOTE: The expressions should be copied, but for this test we can store // them directly. yeval_state_t state; yvec_t* stack = &state.call_stack; YVEC_INIT(stack, 4, yexpr_t); YVEC_PUSH(stack, &let_call); yexpr_t result = ybuiltin_run(YBUILTIN_LET, &state); yexpr_debug(&result); assert(result.typ == YEXPR_UNDEF); assert(stack->len == 0); yvalue_t* stored = yvalue_get(ref); assert(stored->typ == YVALUE_EXPR); assert(stored->value.expr.typ == YEXPR_ATOM); assert(stored->value.expr.value.atom == val_expr.value.atom); // Type mismatch exception. yexpr_set_number(YVEC_AT(&let_call.value.list, 1, yexpr_t), 124); YVEC_PUSH(stack, &let_call); result = ybuiltin_run(YBUILTIN_LET, &state); yexpr_debug(&result); assert(result.typ == YEXPR_EXCEPTION); assert(stack->len == 0); yexpr_destroy(&result); // Not enough arguments on stack. result = ybuiltin_run(YBUILTIN_LET, &state); assert(result.typ == YEXPR_EXCEPTION); fputs(ystr_str(&result.value.str), stderr); fputs("\n", stderr); assert(0 == ystr_cmp_str( &result.value.str, "BUILTIN:LET: BUG: not enough arguments on call stack: NULL")); yexpr_destroy(&result); yexpr_destroy(&ref_expr); yexpr_destroy(&val_expr); yexpr_destroy(&let_call); yvec_destroy(stack); }; void test_builtin_let_parsed(void) { fprintf(stderr, "test_builtin_let_parsed ============\n"); ystr_t input = ystr_new("(let my-var (1 2 3))"), error = ystr_new(NULL); yexpr_t program = yexpr_new(), *let_expr; assert(yparse_str(&input, &program, &error)); ypreprocess_resolve_builtins(&program); let_expr = YVEC_AT(&program.value.list, 0, yexpr_t); yeval_state_t state; YVEC_INIT(&state.call_stack, 4, yexpr_t); YVEC_PUSH(&state.call_stack, let_expr); yexpr_t result = ybuiltin_run(YBUILTIN_LET, &state); assert(result.typ == YEXPR_UNDEF); assert(state.call_stack.len == 0); // Retrieve stored value. yref_t my_var_ref = yref_new_c("my-var"); yvalue_t* stored = yvalue_get(my_var_ref); assert(stored->typ == YVALUE_EXPR); assert(stored->value.expr.typ == YEXPR_LIST); assert(stored->value.expr.value.list.len == 3); assert(YVEC_AT(&stored->value.expr.value.list, 1, yexpr_t)->value.n == 2); yexpr_destroy(&result); yexpr_destroy(&program); yref_destroy(&my_var_ref); yvec_destroy(&state.call_stack); ystr_destroy(&input); ystr_destroy(&error); } void test_builtin_let_recall(void) { fprintf(stderr, "test_builtin_let_recall ============\n"); ystr_t input = ystr_new( "(let my-var ('a 'b) \"cd\")" "(my-var)"); ystr_t error = ystr_new(NULL); yexpr_t program = yexpr_new(); assert(yparse_str(&input, &program, &error)); assert(YEXPR_LIST == program.typ && 2 == program.value.list.len); ypreprocess_resolve_builtins(&program); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; // Evaluate whole program yexpr_t result = yeval_list_return_last(&state, &program.value.list, 0); // Check that result is "cd" assert(YEXPR_LIST == result.typ && 1 == result.value.list.len); yexpr_t* inner = YVEC_AT(&result.value.list, 0, yexpr_t); assert(YEXPR_STRING == inner->typ); yexpr_debug(inner); assert(0 == ystr_cmp_str(&inner->value.str, "cd")); yvec_destroy(&state.call_stack); yexpr_destroy(&result); ystr_destroy(&error); ystr_destroy(&input); yexpr_destroy(&program); } void test_builtin_eq(void) { fprintf(stderr, "test_builtin_eq ============\n"); ystr_t input = ystr_new( "(let var-a 1)" "(let var-b 'atom)" "(let var-c \"string\")" "((== var-a 1) (== 1 var-a) (== var-a var-a) (== for for) (== (1 2 3) " "(var-a 2 3)) (== var-b 'atom) (== " "'atom2 'atom2) (== " "var-c \"string\"))"); ystr_t error = ystr_new(NULL); yexpr_t program = yexpr_new(); assert(yparse_str(&input, &program, &error)); yexpr_debug(&program); ypreprocess(&program); yexpr_debug(&program); yeval_state_t state; YVEC_INIT(&state.call_stack, 4, yexpr_t); yexpr_t result = yeval_list_return_last(&state, &program.value.list, 0); assert(result.typ == YEXPR_LIST); yexpr_debug(&result); for (size_t i = 0; i < result.value.list.len; i++) { yexpr_t* elem = YVEC_AT(&result.value.list, i, yexpr_t); assert(YEXPR_ATOM == elem->typ && yatom_get_or_add("true") == elem->value.atom); } yexpr_destroy(&result); yexpr_destroy(&program); ystr_destroy(&input); ystr_destroy(&error); yvec_destroy(&state.call_stack); } void test_builtin_print(void) { fprintf(stderr, "test_builtin_print ============\n"); char buf[512]; memset(buf, 0, 512); FILE* output = fmemopen(buf, 512, "w"); ybuiltin_set_output(output); ystr_t input = ystr_new( "(let a \"hello\")" "(let b 'world)" "(print 1 a b)"); ystr_t expected = ystr_new("1 \"hello\" world"); ystr_t error = ystr_new(NULL); yexpr_t program = yexpr_new(); assert(yparse_str(&input, &program, &error)); ypreprocess(&program); yeval_state_t state; YVEC_INIT(&state.call_stack, 4, yexpr_t); yexpr_t result = yeval_list_return_last(&state, &program.value.list, 0); assert(result.typ == YEXPR_UNDEF); fclose(output); assert(0 == ystr_cmp_str(&expected, buf)); ystr_destroy(&expected); yexpr_destroy(&result); yexpr_destroy(&program); ystr_destroy(&input); ystr_destroy(&error); yvec_destroy(&state.call_stack); } int main(void) { test_builtin_translate(); test_builtin_for(); test_builtin_for_complex(); test_builtin_for_noresult(); test_builtin_let(); test_builtin_let_parsed(); test_builtin_let_recall(); test_builtin_eq(); test_builtin_print(); yvalue_free_all(); yatom_free_all(); return 0; }