/* * NAME: optimize->expr() * DESCRIPTION: optimize an expression */ static Uint opt_expr(node **m, bool pop) { Uint d1, d2, i; node *n; node **oldside, *side; Uint olddepth; n = *m; switch (n->type) { case N_FLOAT: case N_GLOBAL: case N_INT: case N_LOCAL: case N_STR: case N_NIL: return !pop; case N_TOINT: case N_CAST: return opt_expr(&n->l.left, FALSE); case N_NEG: case N_UMIN: return max2(opt_expr(&n->l.left, FALSE), 2); case N_CATCH: oldside = side_start(&side, &olddepth); d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { n->l.left = (node *) NULL; } d1 = max2(d1, side_end(&n->l.left, side, oldside, olddepth)); if (d1 == 0) { *m = node_nil(); (*m)->line = n->line; return !pop; } return d1; case N_TOFLOAT: if (n->l.left->mod != T_INT) { return opt_expr(&n->l.left, FALSE); } /* fall through */ case N_NOT: case N_TST: if (pop) { *m = n->l.left; return opt_expr(m, TRUE); } return opt_expr(&n->l.left, FALSE); case N_TOSTRING: if (pop && (n->l.left->mod == T_INT || n->l.left->mod == T_FLOAT)) { *m = n->l.left; return opt_expr(m, TRUE); } return opt_expr(&n->l.left, FALSE); case N_LVALUE: return opt_lvalue(n->l.left); case N_ADD_EQ_1: case N_ADD_EQ_1_INT: case N_ADD_EQ_1_FLOAT: case N_SUB_EQ_1: case N_SUB_EQ_1_INT: case N_SUB_EQ_1_FLOAT: return opt_lvalue(n->l.left) + 1; case N_MIN_MIN: if (pop) { n->type = N_SUB_EQ_1; } return opt_lvalue(n->l.left) + 1; case N_MIN_MIN_INT: if (pop) { n->type = N_SUB_EQ_1_INT; } return opt_lvalue(n->l.left) + 1; case N_MIN_MIN_FLOAT: if (pop) { n->type = N_SUB_EQ_1_FLOAT; } return opt_lvalue(n->l.left) + 1; case N_PLUS_PLUS: if (pop) { n->type = N_ADD_EQ_1; } return opt_lvalue(n->l.left) + 1; case N_PLUS_PLUS_INT: if (pop) { n->type = N_ADD_EQ_1_INT; } return opt_lvalue(n->l.left) + 1; case N_PLUS_PLUS_FLOAT: if (pop) { n->type = N_ADD_EQ_1_FLOAT; } return opt_lvalue(n->l.left) + 1; case N_FUNC: m = &n->l.left->r.right; n = *m; if (n == (node *) NULL) { return 1; } d1 = 0; for (i = 0; n->type == N_PAIR; ) { oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left, side, oldside, olddepth)); m = &n->r.right; n = n->l.left; i += (n->type == N_LVALUE || (n->type == N_COMMA && n->r.right->type == N_LVALUE)) ? 6 : 1; n = *m; } if (n->type == N_SPREAD) { m = &n->l.left; } oldside = side_start(&side, &olddepth); d2 = opt_expr(m, FALSE); d1 = max3(d1, i + d2, i + side_end(m, side, oldside, olddepth)); n = *m; if (n->type == N_LVALUE || (n->type == N_COMMA && n->r.right->type == N_LVALUE)) { d1 += 2; } return d1; case N_INSTANCEOF: return opt_expr(&n->l.left, FALSE) + 1; case N_GE: case N_GT: case N_LE: case N_LT: if (n->l.left->mod != n->r.right->mod) { return max2(opt_expr(&n->l.left, FALSE), opt_expr(&n->r.right, FALSE) + 1); } /* fall through */ case N_EQ: case N_NE: if (pop) { d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { *m = n->r.right; return opt_expr(m, TRUE); } d2 = opt_expr(&n->r.right, TRUE); if (d2 == 0) { *m = n->l.left; return d1; } n->type = N_COMMA; side_add(m, d1); return d2; } return opt_binop(m); case N_DIV_INT: case N_MOD_INT: if (n->r.right->type == N_INT && n->r.right->l.number == 0) { d1 = opt_binop(m); return (d1 == 1) ? !pop : d1; } /* fall through */ case N_ADD_INT: case N_ADD_FLOAT: case N_AND_INT: case N_DIV_FLOAT: case N_EQ_INT: case N_EQ_FLOAT: case N_GE_INT: case N_GE_FLOAT: case N_GT_INT: case N_GT_FLOAT: case N_LE_INT: case N_LE_FLOAT: case N_LSHIFT_INT: case N_LT_INT: case N_LT_FLOAT: case N_MULT_INT: case N_MULT_FLOAT: case N_NE_INT: case N_NE_FLOAT: case N_OR_INT: case N_RSHIFT_INT: case N_SUB_INT: case N_SUB_FLOAT: case N_XOR_INT: if (pop) { d1 = opt_expr(&n->l.left, TRUE); if (d1 == 0) { *m = n->r.right; return opt_expr(m, TRUE); } d2 = opt_expr(&n->r.right, TRUE); if (d2 == 0) { *m = n->l.left; return d1; } n->type = N_COMMA; side_add(m, d1); return d2; } /* fall through */ case N_ADD: case N_AND: case N_DIV: case N_LSHIFT: case N_MOD: case N_MULT: case N_OR: case N_RSHIFT: case N_SUB: case N_SUM: case N_XOR: d1 = opt_binop(m); return (d1 == 1) ? !pop : d1; case N_INDEX: if (n->l.left->type == N_STR && n->r.right->type == N_INT) { if (n->r.right->l.number < 0 || n->r.right->l.number >= (long) n->l.left->l.string->len) { return 2; } node_toint(n, (Int) str_index(n->l.left->l.string, (long) n->r.right->l.number)); return !pop; } if (n->l.left->type == N_FUNC && n->r.right->mod == T_INT) { if (n->l.left->r.number == kd_status) { n->type = N_FUNC; if (n->l.left->l.left->r.right != (node *) NULL) { /* status(obj)[i] */ n = n->l.left; n->type = N_STR; n->r.right = n->l.left; n->l.string = n->l.left->l.string; n = n->r.right; n->type = N_PAIR; n->l.left = n->r.right; n->r.right = (*m)->r.right; (*m)->r.number = ((long) KFCALL << 24) | KF_STATUSO_IDX; } else { /* status()[i] */ n->l.left = n->l.left->l.left; n->l.left->r.right = n->r.right; n->r.number = ((long) KFCALL << 24) | KF_STATUS_IDX; } return opt_expr(m, pop); } if (n->l.left->r.number == kd_call_trace) { /* call_trace()[i] */ n->type = N_FUNC; n->l.left = n->l.left->l.left; n->l.left->r.right = n->r.right; n->r.number = ((long) KFCALL << 24) | KF_CALLTR_IDX; return opt_expr(m, pop); } } return max3(opt_expr(&n->l.left, FALSE), opt_expr(&n->r.right, FALSE) + 1, 3); case N_ADD_EQ: case N_ADD_EQ_INT: case N_ADD_EQ_FLOAT: case N_AND_EQ: case N_AND_EQ_INT: case N_DIV_EQ: case N_DIV_EQ_INT: case N_DIV_EQ_FLOAT: case N_LSHIFT_EQ: case N_LSHIFT_EQ_INT: case N_MOD_EQ: case N_MOD_EQ_INT: case N_MULT_EQ: case N_MULT_EQ_INT: case N_MULT_EQ_FLOAT: case N_OR_EQ: case N_OR_EQ_INT: case N_RSHIFT_EQ: case N_RSHIFT_EQ_INT: case N_SUB_EQ: case N_SUB_EQ_INT: case N_SUB_EQ_FLOAT: case N_SUM_EQ: case N_XOR_EQ: case N_XOR_EQ_INT: return opt_asgnexp(m, pop); case N_ASSIGN: if (n->l.left->type == N_AGGR) { d2 = 0; for (n = n->l.left->l.left; n->type == N_PAIR; n = n->r.right) { d1 = opt_lvalue(n->l.left); d2 += 2 + ((d1 < 4) ? d1 : 4); } d1 = opt_lvalue(n); d2 += 2 + ((d1 < 4) ? d1 : 4); return d2 + max2(2, opt_expr(&(*m)->r.right, FALSE)); } else { d1 = opt_lvalue(n->l.left); return max2(d1, ((d1 < 4) ? d1 : 4) + opt_expr(&n->r.right, FALSE)); } case N_COMMA: side_add(m, opt_expr(&n->l.left, TRUE)); return opt_expr(m, pop); case N_LAND: d1 = opt_cond(&n->l.left, FALSE); if (n->l.left->flags & F_CONST) { if (!opt_ctest(n->l.left)) { /* false && x */ *m = n->l.left; return !pop; } /* true && x */ n->type = N_TST; n->l.left = n->r.right; return opt_expr(m, pop); } oldside = side_start(&side, &olddepth); d2 = opt_cond(&n->r.right, pop); if (d2 == 0) { n->r.right = (node *) NULL; } d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth)); if (d2 == 0) { *m = n->l.left; return opt_expr(m, TRUE); } if (n->r.right->flags & F_CONST) { if (pop) { *m = n->l.left; return opt_expr(m, TRUE); } if (!opt_ctest(n->r.right)) { /* x && false */ n->type = N_COMMA; return opt_expr(m, FALSE); } /* x && true */ n->type = N_TST; return d1; } if (n->r.right->type == N_COMMA) { n = n->r.right; if ((n->r.right->flags & F_CONST) && !opt_ctest(n->r.right)) { /* x && (y, false) --> (x && y, false) */ (*m)->r.right = n->l.left; n->l.left = *m; *m = n; return opt_expr(m, pop); } } return max2(d1, d2); case N_LOR: d1 = opt_cond(&n->l.left, FALSE); if (n->l.left->flags & F_CONST) { if (opt_ctest(n->l.left)) { /* true || x */ *m = n->l.left; return !pop; } /* false || x */ n->type = N_TST; n->l.left = n->r.right; return opt_expr(m, pop); } oldside = side_start(&side, &olddepth); d2 = opt_cond(&n->r.right, pop); if (d2 == 0) { n->r.right = (node *) NULL; } d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth)); if (d2 == 0) { *m = n->l.left; return opt_expr(m, TRUE); } if (n->r.right->flags & F_CONST) { if (pop) { *m = n->l.left; return opt_expr(m, TRUE); } if (opt_ctest(n->r.right)) { /* x || true */ n->type = N_COMMA; return opt_expr(m, FALSE); } /* x || false */ n->type = N_TST; return d1; } if (n->r.right->type == N_COMMA) { n = n->r.right; if ((n->r.right->flags & F_CONST) && opt_ctest(n->r.right)) { /* x || (y, true) --> (x || y, true) */ (*m)->r.right = n->l.left; n->l.left = *m; *m = n; return opt_expr(m, pop); } } return max2(d1, d2); case N_QUEST: i = opt_cond(&n->l.left, FALSE); if (n->l.left->flags & F_CONST) { if (opt_ctest(n->l.left)) { *m = n->r.right->l.left; } else { *m = n->r.right->r.right; } return opt_expr(m, pop); } if (n->l.left->type == N_COMMA && (n->l.left->r.right->flags & F_CONST)) { side_add(&n->l.left, i); if (opt_ctest(n->l.left)) { *m = n->r.right->l.left; } else { *m = n->r.right->r.right; } return opt_expr(m, pop); } n = n->r.right; oldside = side_start(&side, &olddepth); d1 = opt_expr(&n->l.left, pop); if (d1 == 0) { n->l.left = (node *) NULL; } d1 = max2(d1, side_end(&n->l.left, side, oldside, olddepth)); if (d1 == 0) { n->l.left = (node *) NULL; } oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->r.right, pop); if (d2 == 0) { n->r.right = (node *) NULL; } d2 = max2(d2, side_end(&n->r.right, side, oldside, olddepth)); if (d2 == 0) { n->r.right = (node *) NULL; } return max3(i, d1, d2); case N_RANGE: d1 = opt_expr(&n->l.left, FALSE); d2 = 1; if (n->r.right->l.left != (node *) NULL) { d2 = opt_expr(&n->r.right->l.left, FALSE); if ((n->l.left->mod == T_STRING || (n->l.left->mod & T_REF) != 0) && n->r.right->l.left->type == N_INT && n->r.right->l.left->l.number == 0) { /* * str[0 .. x] or arr[0 .. x] */ n->r.right->l.left = (node *) NULL; d2 = 1; } else { d1 = max2(d1, d2 + 1); d2 = 2; } } if (n->r.right->r.right != (node *) NULL) { d1 = max2(d1, d2 + opt_expr(&n->r.right->r.right, FALSE)); } if (n->l.left->type == N_STR) { long from, to; if (n->r.right->l.left == (node *) NULL) { from = 0; } else { if (n->r.right->l.left->type != N_INT) { return d1; } from = n->r.right->l.left->l.number; } if (n->r.right->r.right == (node *) NULL) { to = n->l.left->l.string->len - 1; } else { if (n->r.right->r.right->type != N_INT) { return d1; } to = n->r.right->r.right->l.number; } if (from >= 0 && from <= to + 1 && to < (long) n->l.left->l.string->len) { node_tostr(n, str_range(n->l.left->l.string, from, to)); return !pop; } return d1; } return max2(d1, 3); case N_AGGR: if (n->mod == T_MAPPING) { n = n->l.left; if (n == (node *) NULL) { return 1; } d1 = 0; for (i = 0; n->type == N_PAIR; i += 2) { oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left->l.left, side, oldside, olddepth)); oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left->r.right, FALSE); d1 = max3(d1, i + 1 + d2, i + 1 + side_end(&n->l.left->r.right, side, oldside, olddepth)); n = n->r.right; } oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left, side, oldside, olddepth)); oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->r.right, FALSE); return max3(d1, i + 1 + d2, i + 1 + side_end(&n->r.right, side, oldside, olddepth)); } else { m = &n->l.left; n = *m; if (n == (node *) NULL) { return 1; } d1 = 0; for (i = 0; n->type == N_PAIR; i++) { oldside = side_start(&side, &olddepth); d2 = opt_expr(&n->l.left, FALSE); d1 = max3(d1, i + d2, i + side_end(&n->l.left, side, oldside, olddepth)); m = &n->r.right; n = *m; } oldside = side_start(&side, &olddepth); d2 = opt_expr(m, FALSE); return max3(d1, i + d2, i + side_end(m, side, oldside, olddepth)); } } # ifdef DEBUG fatal("unknown expression type %d", n->type); # endif return 0; }
void test() { test_code("VERSION", node_str(VERSION)); test_code("PLATFORM", node_str(PLATFORM)); test_code("ARCH", node_str(ARCH)); test_code("COPYRIGHT", node_str(COPYRIGHT)); test_code("\'()", node_empty_list()); test_code("(quote)", node_empty_list()); test_code("(+ 1 2)", node_num(3)); test_code("(- 9 5)", node_num(4)); test_code("(* 1 5)", node_num(5)); test_code("(/ 12 2)", node_num(6)); test_code("(% 7 8)", node_num(7)); test_code("(+ 1.5 1.5)", node_num(3)); test_code("1e+300", node_num(1e+300)); test_code("(string 1e+300)", node_str("1e+300")); test_code("(** 2 3 2)", node_num(64)); test_code("(sqrt 4)", node_num(2)); test_code("(sin (/ pi 2))", node_num(1)); test_code("(cos pi)", node_num(-1)); test_code("(ln e)", node_num(1)); test_code("(log 100)", node_num(2)); test_code("(not true)", node_nil()); test_code("(not nil)", node_true()); test_code("(and true true)", node_true()); test_code("(and true nil)", node_nil()); test_code("(and true true true nil)", node_nil()); test_code("(and nil true)", node_nil()); test_code("(and nil nil)", node_nil()); test_code("(or true nil)", node_true()); test_code("(or true true)", node_true()); test_code("(or nil true)", node_true()); test_code("(or nil nil)", node_nil()); test_code("(or nil nil nil true)", node_true()); node *l=node_empty_list(); l=node_append(l, node_num(1)); l=node_append(l, node_num(2)); l=node_append(l, node_num(3)); test_code("(push \'(2 3) 1)", l); test_code("(push (quote 2 3) 1)", l); test_code("(push \"at\" \"c\")", node_str("cat")); test_code("(set \'a \'(2 3)) (push a 1) a", l); test_code("(set \'b (pop a)) b", node_num(1)); l=node_empty_list(); l=node_append(l, node_num(2)); l=node_append(l, node_num(3)); test_code("a", l); test_code("(exists? x)", node_nil()); test_code("(set \'x 5) (exists? x)", node_true()); test_code("(string nil)", node_str("nil")); test_code("(string 5)", node_str("5")); test_code("(string 3.14)", node_str("3.14")); test_code("(string \'(1 2 3))", node_str("(1 2 3)")); test_code("(string \"hi\")", node_str("hi")); test_code("(chomp \"Herb\\n\")", node_str("Herb")); test_code("(chomp \"Herb\\r\")", node_str("Herb")); test_code("(chomp \"Herb\\r\\n\")", node_str("Herb")); test_code("(chomp \"Herb\")", node_str("Herb")); test_code("(chop \"Herb\\n\")", node_str("Herb")); test_code("(chop \"Herb\\r\")", node_str("Herb")); test_code("(chop \"Herb\")", node_str("Her")); test_code("(atom? 1)", node_true()); test_code("(length 1)", node_num(0)); test_code("(compare 1 2)", node_num(-1)); test_code("(compare nil nil)", node_num(0)); test_code("(compare \'(1 2) \'(1 2))", node_num(0)); test_code("(< -1 0)", node_true()); test_code("(< 1 2)", node_true()); test_code("(> 2 1)", node_true()); test_code("(< 2 1)", node_nil()); test_code("(<= 1 1)", node_true()); test_code("(>= 2 2)", node_true()); test_code("(= 1 1)", node_true()); test_code("(= 1 2)", node_nil()); test_code("(= (copy \'(1 2 3)) \'(1 2 3))", node_true()); test_code("(= nil true)", node_nil()); test_code("(!= nil true)", node_true()); test_code("(= (copy +) +)", node_true()); l=node_empty_list(); l=node_append(l, node_num(1)); l=node_append(l, node_num(2)); l=node_append(l, node_num(3)); test_code("(append \'(1 2) 3)", l); test_code("(prepend \'(2 3) 1)", l); test_code("(eval)", node_nil()); test_code("(eval 1)", node_num(1)); test_code("(eval \'(1 2 3))", node_nil()); test_code("(eval \'(+ 1 1))", node_num(2)); test_code("(eval \'(eval \'(+ 1 1)))", node_num(2)); node *calculation=node_empty_list(); calculation=node_append(calculation, node_id("+")); calculation=node_append(calculation, node_num(1)); calculation=node_append(calculation, node_num(1)); test_code("\'(+ 1 1)", calculation); test_code("(cat \'(1) \'(2) \'(3))", l); test_code("(cat \'() \'(1 2) \'(3))", l); test_code("(cat \'(1 2) \'(3) \'())", l); test_code("(cat \"c\" \"a\" \"t\")", node_str("cat")); test_code("(cat \"\" \"ca\" \"t\")", node_str("cat")); test_code("(cat \"ca\" \"t\" \"\")", node_str("cat")); test_code("(length \"hi\")", node_num(2)); l=node_empty_list(); l=node_append(l, node_num(1)); l=node_append(l, node_num(2)); test_code("\'(1 2)", l); test_code("(atom? \'(1 2))", node_nil()); test_code("(length \'(1 2))", node_num(2)); test_code("(empty? nil)", node_true()); test_code("(empty? \'())", node_true()); test_code("(empty? \'(1))", node_nil()); test_code("(first \'(1 2 3))", node_num(1)); test_code("(first \"abc\")", node_str("a")); test_code("(number \"-1\")", node_num(-1)); test_code("(set \'a 1) (+ a 1)", node_num(2)); test_code("z", node_nil()); test_code("(needs-closing-paren", node_nil()); test_code("(- (* 2 2 2 2 2 2 2 2 2 2) 1022)", node_num(2)); test_code("(> pi 3)", node_true()); test_code("(= pi 3)", node_nil()); test_code("(< e 3)", node_true()); test_code("(= e 3)", node_nil()); test_code("(> (time) 0)", node_true()); l=node_empty_list(); l=node_append(l, node_nil()); l=node_append(l, node_true()); test_code("\'(nil true)", l); test_code("(set \'a \'(1 2 3)) (first a)", node_num(1)); l=node_empty_list(); l=node_append(l, node_num(2)); l=node_append(l, node_num(3)); test_code("(set \'a \'(1 2 3)) (rest a)", l); test_code("(set \'a \'(1 2 3)) (last a)", node_num(3)); test_code("(list? a)", node_true()); test_code("(atom? a)", node_nil()); test_code("(set \'3 2)", node_nil()); test_code("(* 3 3)", node_num(9)); test_code("(index \"robert\" \"bert\")", node_num(2)); test_code("(index \'(1 2 3) 1)", node_num(0)); test_code("(index \'(1 2 3) 4)", node_num(-1)); test_code("(index \"a b c\" \"\")", node_num(-1)); test_code("(in? \'(1 2 3) 1)", node_true()); test_code("(in? \'(1 2 3) 4)", node_nil()); test_code("(at \'(1 2 3) 0)", node_num(1)); test_code("(at \'(1 2 3) 1)", node_num(2)); test_code("(at \'(1 2 3) 2)", node_num(3)); test_code("(at \'(1 2 3) 3)", node_nil()); test_code("(count \'(1 2 3) 1)", node_num(1)); test_code("(count \'(1 1 1) 1)", node_num(3)); test_code("(count \'(1 2 3) 4)", node_num(0)); test_code("(count \'() 1)", node_num(0)); l=node_empty_list(); l=node_append(l, node_str("a")); l=node_append(l, node_str("b")); l=node_append(l, node_str("c")); test_code("(split \"a b c\" \" \")", l); l=node_empty_list(); l=node_append(l, node_str("a b c")); test_code("(split \"a b c\" \"!\")", l); test_code("(split \"a b c\" \"\")", l); test_code("(join \'(\"a\" \"b\" \"c\") \" \")", node_str("a b c")); test_code("(join \'(\"a\" \"b\" \"c\") \", \")", node_str("a, b, c")); test_code("(join \'(\"a\" \"b\" \"c\") \"\")", node_str("abc")); test_code("(join \'(\"a\") \" \")", node_str("a")); test_code("(join \'() \" \")", node_str("")); node *k=node_empty_list(); k=node_append(k, node_str("a")); k=node_append(k, node_str("b")); k=node_append(k, node_str("c")); node *v=node_empty_list(); v=node_append(v, node_num(1)); v=node_append(v, node_num(2)); v=node_append(v, node_num(3)); node *h=node_hash(k, v); test_code("(set \'a (hash \'(\"a\" \"b\" \"c\") \'(1 2 3)))", h); test_code("(hash? a)", node_true()); test_code("(hash? \'(1 2))", node_nil()); test_code("(hash-keys a)", k); test_code("(hash-values a)", v); test_code("(set \'a (hash \'() \'())) (hash-set a \"guy\" \"robert\") (hash-get a \"guy\")", node_str("robert")); test_code("(hash? (env))", node_true()); test_code("(env \"COOLNAME\" \"Bobby\")", node_str("Bobby")); test_code("(env \"COOLNAME\")", node_str("Bobby")); test_code("(env \"COOLNAME\" \"red=blue\")", node_str("red=blue")); test_code("(env \"COOLNAME\")", node_str("red=blue")); test_code("(hash? (env))", node_true()); test_code("(if (< 1 2) 1 2)", node_num(1)); test_code("(if (< 1 2) 1)", node_num(1)); test_code("(if (> 1 2) 1 2)", node_num(2)); test_code("(if (> 1 2) 1)", node_nil()); test_code("(unless (< 1 2) 1 2)", node_num(2)); test_code("(unless (< 1 2) 1)", node_nil()); test_code("(unless (> 1 2) 1 2)", node_num(1)); test_code("(unless (> 1 2) 1)", node_num(1)); test_code("(set \'i 0)", node_num(0)); test_code("(while (< i 5) (set \'i (+ i 1)))", node_num(5)); test_code("(for (j 0 5) j)", node_num(4)); test_code("(block (+ 2 2) (- 4 1) (* 1 2) (/ 5 5))", node_num(1)); test_code("(let (\'y 3) (+ y 2))", node_num(5)); test_code("y", node_nil()); test_code("(set \'f (lambda (x) (+ x 1))) (f 4)", node_num(5)); node *vars=node_empty_list(); vars=node_append(vars, node_id("x")); vars=node_append(vars, node_id("y")); node *exps=node_empty_list(); exps=node_append(exps, node_id("*")); exps=node_append(exps, node_id("x")); exps=node_append(exps, node_id("y")); node *temp=node_empty_list(); temp=node_append(temp, exps); node *lambda=node_lambda(vars, temp); test_code("(lambda (x y) (* x y))", lambda); test_code("((lambda (x y) (* x y)) 2 3)", node_num(6)); test_code("(set \'multiply (lambda (x y) (* x y))) (multiply 5)", node_nil()); test_code("(atom? multiply)", node_true()); test_code("(set \'a (lambda () 5)) (a)", node_num(5)); test_code("(set \'a (lambda (x y) (+ x y) (- x y) (* x y) (/ x y))) (a 1 2)", node_num(0.5)); vars=node_empty_list(); vars=node_append(vars, node_id("x")); exps=node_empty_list(); exps=node_append(exps, node_id("*")); exps=node_append(exps, node_id("x")); exps=node_append(exps, node_id("x")); temp=node_empty_list(); temp=node_append(temp, exps); node *def=node_lambda(vars, temp); test_code("(def (square x) (* x x))", def); test_code("(square)", node_nil()); test_code("(square 4)", node_num(16)); test_code("(set \'plus +)", node_builtin("+", node_add)); test_code("(set \'+ -)", node_builtin("-", node_sub)); test_code("(+ 1 1)", node_num(0)); test_code("(set '+ plus)", node_builtin("+", node_add)); test_code("(+ 1 1)", node_num(2)); if (FAILURES<1) printf("ALL %d TESTS PASS\n", SUCCESSES); else printf("%d TESTS FAIL\n", FAILURES); }