void test_lazy()
{
#ifdef DEFERRED_CALLS_FIRST_DRAFT
    Branch branch;

    Term* a = branch.compile("a = add(1 2)");
    set_lazy_call(a, true);

    Stack context;
    push_frame(&context, &branch);
    run_interpreter(&context);

    test_equals(get_register(&context, a), ":Unevaluated");

    Frame* frame = push_frame(&context, &branch);
    frame->pc = a->index;
    frame->startPc = frame->pc;
    frame->endPc = frame->pc + 1;
    frame->strategy = ByDemand;
    run_interpreter(&context);

    test_equals(get_register(&context, a), "3");

    reset_stack(&context);
    Term* b = branch.compile("b = add(a a)");
    push_frame(&context, &branch);
    run_interpreter(&context);

    test_equals(get_register(&context, a), "3");
    test_equals(get_register(&context, b), "6");
#endif
}
void repro_source_after_rename()
{
    Branch branch;

    // Simple test
    Term* a = branch.compile("a = 1");

    rename(a, "apple");

    test_equals(get_term_source_text(a), "apple = 1");

    // Rename a function argument
    Term* b = branch.compile("b = 5");
    Term* add = branch.compile("add( b , 10)");

    rename(b, "banana");

    test_equals(get_term_source_text(add), "add( banana , 10)");

    // Rename a function
    Term* myfunc = import_function(&branch, NULL, "def myfunc(int)");
    Term* myfunc_call = branch.compile("myfunc(555)");

    rename(myfunc, "my_renamed_func");

    test_equals(get_term_source_text(myfunc_call), "my_renamed_func(555)");
}
void test_trimmed_state(std::string const& source, std::string const& dest,
    std::string const& expectedTrash)
{
    Branch sourceBranch;
    sourceBranch.compile(source);

    if (test_fail_on_static_error(&sourceBranch))
        return;

    Stack context;
    evaluate_branch(&context, &sourceBranch);

    if (test_fail_on_runtime_error(context))
        return;

    Branch destBranch;
    destBranch.compile(dest);

    if (test_fail_on_static_error(&destBranch))
        return;

    caValue trash;
    strip_orphaned_state(&destBranch, &context.state, &trash);

    if (expectedTrash != trash.toString()) {
        declare_current_test_failed();
        std::cout << "In test " << get_current_test_name() << std::endl;
        std::cout << expectedTrash << " != " << trash.toString() << std::endl;
    }
}
void test_state_is_reset_when_if_fails()
{
    Branch branch;
    Stack context;

    Term* c = branch.compile("c = true");
    branch.compile("if c { state i = 0; i += 1 } else { 'hi' }");

    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{i: 1}]}");

    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{i: 2}]}");

    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{i: 3}]}");

    set_bool(c, false);

    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [null, null]}");

    set_bool(c, true);

    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{i: 1}]}");
}
void assign_output_type()
{
    Branch branch;
    branch.compile("a = [1]");
    Term* assign = branch.compile("a[0] = 2");
    test_equals(assign->type->name, "List");
}
void test_state_is_reset_when_if_fails2()
{
    // Similar to test_state_is_reset_when_if_fails, but this one doesn't
    // have an 'else' block and it uses test_oracle.
    
    internal_debug_function::oracle_clear();

    Branch branch;
    Term* a = branch.compile("a = true");
    
    branch.compile("if a { state s = test_oracle() }");

    internal_debug_function::oracle_send(1);
    internal_debug_function::oracle_send(2);
    internal_debug_function::oracle_send(3);

    Stack context;
    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{s: 1}]}");

    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{s: 1}]}");

    set_bool(a, false);
    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [null, null]}");

    set_bool(a, true);
    evaluate_branch(&context, &branch);
    test_equals(&context.state, "{_if_block: [{s: 2}]}");
}
void for_loop_output_type()
{
    Branch branch;
    branch.compile("a = 1");
    branch.compile("for i in [1] { a = 2 }");

    test_equals(branch["a"]->type->name, "int");
}
void infer_type_of_append()
{
    Branch branch;
    branch.compile("a = []");
    branch.compile("a.append(1)");
    Term* b = branch.compile("a[0]");
    test_equals(b->type->name, "int");
}
void compare_builtin_types()
{
    Branch branch;
    Term* aFloat = branch.compile("1.2");
    test_assert(term_output_always_satisfies_type(aFloat, unbox_type(FLOAT_TYPE)));
    test_assert(term_output_never_satisfies_type(aFloat, unbox_type(INT_TYPE)));

    Term* anInt = branch.compile("1");
    test_assert(term_output_always_satisfies_type(anInt, unbox_type(FLOAT_TYPE)));
    test_assert(term_output_always_satisfies_type(anInt, unbox_type(INT_TYPE)));
}
Exemple #10
0
void name_visible_iterator_1()
{
    Branch branch;
    branch.compile("a = 1");
    Term* b = branch.compile("b = 1");
    branch.compile("c = 1; d = 1; e = 1");
    branch.compile("b = 2; f = 1; g = 1");

    NameVisibleIterator it(b);
    test_equals(it.current()->name,"c"); test_assert(!it.finished()); ++it;
    test_equals(it.current()->name,"d"); test_assert(!it.finished()); ++it;
    test_equals(it.current()->name,"e"); test_assert(!it.finished()); ++it;
    test_assert(it.finished());
}
void test_execution_with_elif()
{
    Branch branch;

    branch.compile("x = 5");

    branch.compile("if x > 5 { test_spy('Fail') } "
                "elif x < 5 { test_spy('Fail')} "
                "elif x == 5 { test_spy('Success')} "
                "else { test_spy('Fail') }");

    internal_debug_function::spy_clear();
    evaluate_branch(&branch);
    test_assert(&branch);
    test_equals(internal_debug_function::spy_results(), "['Success']");
}
void test_snippet(std::string const& source)
{
    Branch branch;
    branch.compile(source);

    if (test_fail_on_static_error(&branch))
        return;

    Stack context;
    evaluate_branch(&context, &branch);

    if (test_fail_on_runtime_error(context))
        return;

    // Try stripping orphaned state, this should not have an effect.
    caValue trash;
    strip_orphaned_state(&branch, &context.state, &trash);

    if (!is_null(&trash)) {
        std::cout << "Falsely orphaned state in " << get_current_test_name() << std::endl;
        std::cout << "Code = " << source << std::endl;
        std::cout << "Trash = " << trash.toString() << std::endl;
        declare_current_test_failed();
        return;
    }
}
void bug_reproducing_list_after_eval()
{
    // There once was a bug where source repro would fail when using a list
    // in a vectorized function, but only after that piece of code had been
    // evaluated. This was because vectorize_vv was calling apply() which
    // was changing the 'statement' property of its inputs.
    Branch branch;

    Term* sum = branch.compile("[1 1] + [1 1]");
    Term* in0 = sum->input(0);
    Term* in1 = sum->input(0);

    test_equals(get_term_source_text(in0), "[1 1]");
    test_equals(get_term_source_text(in1), "[1 1]");
    test_equals(get_input_source_text(sum, 0), "[1 1] ");
    test_equals(get_input_source_text(sum, 1), " [1 1]");
    test_equals(get_branch_source_text(&branch), "[1 1] + [1 1]");

    evaluate_branch(&branch);

    test_equals(get_term_source_text(in0), "[1 1]");
    test_equals(get_term_source_text(in1), "[1 1]");
    test_equals(get_input_source_text(sum, 0), "[1 1] ");
    test_equals(get_input_source_text(sum, 1), " [1 1]");

    test_equals(get_branch_source_text(&branch), "[1 1] + [1 1]");
}
Exemple #14
0
void test_custom_object()
{
    g_currentlyAllocated = 0;
    g_totalAllocated = 0;

    Branch branch;
    branch.compile(
        "type MyType; \n"
        "def create_object() -> MyType\n"
        "def check_object(MyType t)\n"
        "s = create_object()\n"
        "check_object(s)\n"
            );

    circa_install_function(&branch, "create_object", create_object);
    circa_install_function(&branch, "check_object", check_object);

    circa_setup_object_type(circa_find_type(&branch, "MyType"),
            sizeof(CustomObject), CustomObjectRelease);

    // Shouldn't allocate any objects before running.
    test_equals(g_currentlyAllocated, 0);
    test_equals(g_totalAllocated, 0);

    Stack stack;
    push_frame(&stack, &branch);
    run_interpreter(&stack);
    test_assert(&stack);
    circa_clear_stack(&stack);

    // Running the script should only cause 1 object allocation.
    test_equals(g_currentlyAllocated, 0);
    test_equals(g_totalAllocated, 1);
}
Exemple #15
0
void test_type_not_prematurely_used()
{
    // Verify that a circa-defined type is not used until interpreter time. Modifying
    // a type's release() handler after there are already instances of it, is not good.
    
    Branch branch;
    branch.compile(
        "type MyType; \n"
        "def f() -> MyType\n"
        "def g(MyType t)\n"
        "s = f()\n"
        "g(s)\n"
        "l = [s s s]\n"
        "type MyCompoundType {\n"
        "  MyType t\n"
        "}\n"
        "state MyType st\n"
        "state MyType st2 = create(MyType)\n"
        );

    Type* myType = (Type*) circa_find_type(&branch, "MyType");
    Type* myCompoundType = (Type*) circa_find_type(&branch, "MyCompoundType");
    test_assert(!myType->inUse);
    test_assert(!myCompoundType->inUse);

    circa::Value value1, value2;
    create(myType, &value1);
    create(myCompoundType, &value2);

    test_assert(myType->inUse);
    test_assert(myCompoundType->inUse);
}
void test_state_simple()
{
    Branch branch;
    Stack context;

    // Simple test, condition never changes
    Term* block = branch.compile("if true { state i = 0; i += 1 }");
    evaluate_branch(&context, &branch);

    caValue *i = context.state.getField("_if_block")->getIndex(0)->getField("i");
    test_assert(i != NULL);
    test_assert(as_int(i) == 1);
    evaluate_branch(&context, &branch);
    i = context.state.getField("_if_block")->getIndex(0)->getField("i");
    test_assert(as_int(i) == 2);
    evaluate_branch(&context, &branch);
    i = context.state.getField("_if_block")->getIndex(0)->getField("i");
    test_assert(as_int(i) == 3);

    // Same test with elif
    branch.clear();
    block = branch.compile("if false {} elif true { state i = 0; i += 1 }");
    evaluate_branch(&context, &branch);
    i = context.state.getField("_if_block")->getIndex(1)->getField("i");
    test_assert(as_int(i) == 1);
    evaluate_branch(&context, &branch);
    i = context.state.getField("_if_block")->getIndex(1)->getField("i");
    test_assert(as_int(i) == 2);
    evaluate_branch(&context, &branch);
    i = context.state.getField("_if_block")->getIndex(1)->getField("i");
    test_assert(as_int(i) == 3);

    // Same test with else
    branch.clear();

    Stack context2;
    block = branch.compile("if false {} else { state i = 0; i += 1 }");
    evaluate_branch(&context2, &branch);
    i = context2.state.getField("_if_block")->getIndex(1)->getField("i");
    test_assert(as_int(i) == 1);
    evaluate_branch(&context2, &branch);
    i = context2.state.getField("_if_block")->getIndex(1)->getField("i");
    test_assert(as_int(i) == 2);
    evaluate_branch(&context2, &branch);
    i = context2.state.getField("_if_block")->getIndex(1)->getField("i");
    test_assert(as_int(i) == 3);
}
void infer_length()
{
    Branch branch;

    caValue result;

    statically_infer_result(branch.compile("length([])"), &result);
    test_equals(&result, "0");
    statically_infer_result(branch.compile("length([1])"), &result);
    test_equals(&result, "1");
    statically_infer_result(branch.compile("length([1 2 3])"), &result);
    test_equals(&result, "3");

    return; // TEST_DISABLED
    statically_infer_result(branch.compile("length([1 2 3].append(3))"), &result);
    test_equals(&result, "4");
}
void test_that_stripping_state_is_recursive()
{
    Branch branch;
    setup(branch);

    branch.compile("if true { state a = 1; state s; s = alloc_handle(s) }");

    Stack context;
    evaluate_branch(&context, &branch);
    test_equals(&g_slots, "[true, false, false]");

    clear_branch(&branch);
    branch.compile("if true { state a = 1 }");
    strip_orphaned_state(&branch, &context.state);

    test_equals(&g_slots, "[false, false, false]");
}
void test_state_inside_if_block()
{
    Branch branch;
    setup(branch);

    branch.compile("state s = null");
    branch.compile("if is_null(s) { s = alloc_handle(s) }");

    Stack context;
    evaluate_branch(&context, &branch);

    test_equals(&g_slots, "[true, false, false]");
    clear_branch(&branch);
    strip_orphaned_state(&branch, &context.state);

    test_equals(&g_slots, "[false, false, false]");
}
void test_if_elif_else()
{
    Branch branch;

    branch.compile("if true { a = 1 } elif true { a = 2 } else { a = 3 } a=a");
    evaluate_branch(&branch);

    test_assert(branch.contains("a"));
    test_equals(branch["a"]->asInt(), 1);

    branch.compile(
        "if false { b = 'apple' } elif false { b = 'orange' } else { b = 'pineapple' } b=b");
    evaluate_branch(&branch);
    test_assert(branch.contains("b"));
    test_assert(branch["b"]->asString() == "pineapple");

    // try one without 'else'
    branch.clear();
    branch.compile("c = 0");
    branch.compile("if false { c = 7 } elif true { c = 8 }; c=c");
    evaluate_branch(&branch);
    test_assert(branch.contains("c"));
    test_assert(branch["c"]->asInt() == 8);

    // try with some more complex conditions
    branch.clear();
    branch.compile("x = 5");
    branch.compile("if x > 6 { compare = 1 } elif x < 6 { compare = -1 } else { compare = 0}");
    branch.compile("compare=compare");
    evaluate_branch(&branch);

    test_assert(branch.contains("compare"));
    test_assert(branch["compare"]->asInt() == -1);
}
void test_in_subroutine_state()
{
    Branch branch;
    setup(branch);

    branch.compile("def hi(any input) { state s = input }");
    branch.compile("state s");
    branch.compile("alloc_handle(@s)");
    branch.compile("hi(s)");

    Stack context;
    evaluate_branch(&context, &branch);

    test_equals(&g_slots, "[true, false, false]");

    set_null(&context.state);

    test_equals(&g_slots, "[false, false, false]");
}
void test_dont_always_rebind_inner_names()
{
    Branch branch;
    branch.compile("if false { b = 1 } elif false { c = 1 } elif false { d = 1 } else { e = 1 }");
    evaluate_branch(&branch);
    test_assert(!branch.contains("b"));
    test_assert(!branch.contains("c"));
    test_assert(!branch.contains("d"));
    test_assert(!branch.contains("e"));
}
Exemple #23
0
void test_refs_are_destruction_safe()
{
    Branch branch;
    Term* a = branch.compile("a = 1");
    caValue ref;
    set_ref(&ref, a);
    test_assert(as_ref(&ref) == a);
    clear_branch(&branch);
    test_assert(as_ref(&ref) == NULL);
}
Exemple #24
0
void test_cast_first_inputs()
{
    // Pass an input of [1] to a branch that expects a compound type.
    // The function will need to cast the [1] to T in order for it to work.

    Branch branch;
    branch.compile("type T { int i }");
    Term* f = branch.compile("def f(T t) -> int { return t.i }");

    Stack context;
    push_frame(&context, function_contents(f));

    caValue* in = circa_input((caStack*) &context, 0);
    circa_set_list(in, 1);
    circa_set_int(circa_index(in, 0), 5);

    run_interpreter(&context);

    test_assert(circa_int(circa_output((caStack*) &context, 0)) == 5);
}
void repro_source_after_append_code()
{
    Branch branch;

    Term* target = branch.compile("target = {}");

    branch.eval("bm = branch_ref(target)");

    branch.eval("bm.append_code({ 1  +  1 })");

    test_equals(get_branch_source_text(nested_contents(target)), " 1  +  1 ");
}
void setup(Branch& branch)
{
    g_slots.resize(numSlots);
    for (int i=0; i < numSlots; i++)
        set_bool(g_slots[i], false);

    handle_t::setup_type(&handle_type);
    set_opaque_pointer(&handle_type.parameter, (void*) on_release_func);

    branch.compile("def alloc_handle(any s) -> any;");
    install_function(branch["alloc_handle"], alloc_handle);
}
void test_with_state()
{
    Branch branch;
    setup(branch);

    test_equals(&g_slots, "[false, false, false]");

    branch.compile("state s");
    branch.compile("alloc_handle(@s)");
    set_branch_in_progress(&branch, false);

    Stack context;
    evaluate_branch(&context, &branch);

    test_equals(&g_slots, "[true, false, false]");

    evaluate_branch(&context, &branch);
    test_equals(&g_slots, "[true, false, false]");

    reset(&context.state);
    test_equals(&g_slots, "[false, false, false]");
}
void test_deleted_state()
{
    Branch branch;
    setup(branch);

    branch.compile("state s");
    branch.compile("alloc_handle(@s)");

    branch.compile("state t");
    branch.compile("alloc_handle(@t)");

    Stack context;
    evaluate_branch(&context, &branch);

    test_equals(&g_slots, "[true, true, false]");

    clear_branch(&branch);
    branch.compile("state t");
    strip_orphaned_state(&branch, &context.state);
    
    test_equals(&g_slots, "[false, true, false]");
}
void test_change_function()
{
    Branch branch;

    // simple test
    Term* a = branch.compile("add(3,3)");
    evaluate_branch(&branch);
    test_assert(as_int(a) == 6);

    change_function(a, KERNEL->get("mult_i"));
    evaluate_branch(&branch);
    test_assert(as_int(a) == 9);
}
Exemple #30
0
void branch_iterator_2_2()
{
    Branch branch;
    branch.compile("a = { b = { c = { d = 3; e = 4; }}}");

    BranchIterator2 it(&branch);
    test_assert(it.current()->name == "a"); test_assert(!it.finished()); ++it;
    test_assert(it.current()->name == "b"); test_assert(!it.finished()); ++it;
    test_assert(it.current()->name == "c"); test_assert(!it.finished()); ++it;
    test_assert(it.current()->name == "d"); test_assert(!it.finished()); ++it;
    test_assert(it.current()->name == "e"); test_assert(!it.finished()); ++it;
    test_assert(it.finished());
}