Exemple #1
0
void modify_branch_so_that_state_access_is_indexed(Branch* branch, int index)
{
    Term* stateInput = find_state_input(branch);
    if (stateInput == NULL)
        return;

    // If the state output is connected directly to state input, then do nothing.
    Term* stateOutput = find_state_output(branch);

    if (stateOutput->input(0) == stateInput)
        return;

    Term* unpackList = apply(branch, FUNCS.unpack_state_from_list, TermList(stateInput));
    unpackList->setIntProp("index", index);
    move_after_inputs(unpackList);

    for (int i=0; i < stateInput->users.length(); i++) {
        Term* term = stateInput->users[i];
        if (term == unpackList)
            continue;
        remap_pointers_quick(term, stateInput, unpackList);
    }

    Term* stateResult = stateOutput->input(0);
    ca_assert(stateResult != NULL);

    Term* packList = apply(branch, FUNCS.pack_state_to_list,
                           TermList(stateInput, stateResult));
    packList->setIntProp("index", index);
    packList->setBoolProp("final", true);
    set_input(stateOutput, 0, packList);
    move_after(packList, stateResult);
}
Exemple #2
0
void block_update_state_type(Block* block)
{
    if (!block_state_type_is_out_of_date(block))
        return;

    // Recreate the state type
    Type* type = create_compound_type();

    // TODO: give this new type a nice name

    for (int i=0; i < block->length(); i++) {
        Term* term = block->get(i);
        if (term == NULL)
            continue;

        if (term->function != FUNCS.unpack_state || FUNCS.unpack_state == NULL)
            continue;

        Term* identifyingTerm = term->input(1);

        caValue* fieldName = get_unique_name(identifyingTerm);
        ca_assert(is_string(fieldName));
        ca_assert(!string_eq(fieldName, ""));

        compound_type_append_field(type, declared_type(term), as_cstring(fieldName));
    }

    block->stateType = type;
    block_remove_property(block, sym_DirtyStateType);

    // Might need to update any existing pack_state calls.
    block_update_pack_state_calls(block);
}
Exemple #3
0
Term* loop_find_condition(Block* block)
{
    Term* conditionCheck = loop_find_condition_check(block);
    if (conditionCheck != NULL)
        return conditionCheck->input(0);
    return NULL;
}
Exemple #4
0
void BlockInputIterator::advanceWhileInvalid()
{
possibly_invalid:

    if (finished())
        return;

    Term* current = blockIterator.current();

    if (current == NULL) {
        blockIterator.advance();
        inputIndex = 0;
        goto possibly_invalid;
    }

    if (inputIndex >= current->numInputs()) {
        blockIterator.advance();
        inputIndex = 0;
        goto possibly_invalid;
    }

    if (current->input(inputIndex) == NULL) {
        inputIndex++;
        goto possibly_invalid;
    }
}
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 #6
0
bool term_is_observable_after(Term* term, Term* location)
{
    // Check if "term" can be observed after the "location".
    //
    // Typically, "location" uses "term" as an input, and we're trying to decide
    // whether the call at "location" can move/consume the value.

    if (term_is_observable_for_special_reasons(term))
        return true;

    for (int i=0; i < user_count(term); i++) {
        Term* user = term_user(term, i);

        if (user->function == FUNCS.upvalue)
            return true;

        if (terms_are_in_different_switch_conditions(location, user))
            continue;

        if (term_accesses_input_from_inside_loop(user, term)) {

            bool userOnlyAccessesOnFirstIteration = is_input_placeholder(user)
                && user->numInputs() == 2
                && user->input(1) != term;

            if (!userOnlyAccessesOnFirstIteration)
                return true;
        }

        if (is_located_after(user, location))
            return true;
    }
 
    return false;
}
Exemple #7
0
void branch_update_state_type(Branch* branch)
{
    if (branch_state_type_is_out_of_date(branch)) {

        // TODO: Handle the case where the stateType should go from non-NULL to NULL

        // Recreate the state type
        Type* type = create_compound_type();

        // TODO: give this new type a nice name

        for (int i=0; i < branch->length(); i++) {
            Term* term = branch->get(i);
            if (term == NULL)
                continue;

            if (term->function != FUNCS.unpack_state || FUNCS.unpack_state == NULL)
                continue;

            Term* identifyingTerm = term->input(1);

            compound_type_append_field(type, declared_type(term), unique_name(identifyingTerm));
        }

        branch->stateType = type;

        // Might need to update any existing pack_state calls.
        branch_update_existing_pack_state_calls(branch);
    }
}
Exemple #8
0
Term* if_block_append_case(Term* ifBlock, Term* input)
{
    Branch* contents = nested_contents(ifBlock);
    int insertPos = 0;
    for (int i=0; i < contents->length(); i++) {
        Term* term = contents->get(i);

        if (term->function == FUNCS.input)
            insertPos = term->index + 1;

        // Insert position is right after the last non-default case.
        if (term->function == FUNCS.case_func && term->input(0) != NULL)
            insertPos = term->index + 1;
    }

    Term* newCase = apply(contents, FUNCS.case_func, TermList(input));
    contents->move(newCase, insertPos);

    // Add existing input placeholders to this case
    for (int i=0;; i++) {
        Term* placeholder = get_input_placeholder(contents, i);
        if (placeholder == NULL) break;
        Term* localPlaceholder = append_input_placeholder(nested_contents(newCase));
        change_declared_type(localPlaceholder, placeholder->type);
    }

    return newCase;
}
Exemple #9
0
void repoint_terms_to_use_input_placeholders(Branch* contents)
{
    // Visit every term
    for (int i=0; i < contents->length(); i++) {
        Term* term = contents->get(i);

        // Visit every input
        for (int inputIndex=0; inputIndex < term->numInputs(); inputIndex++) {
            Term* input = term->input(inputIndex);
            if (input == NULL)
                continue;
            
            // If the input is outside this branch, then see if we have a named
            // input that could be used instead.
            if (input->owningBranch == contents || input->name == "")
                continue;

            Term* replacement = find_input_placeholder_with_name(contents, input->name.c_str());
            if (replacement == NULL)
                continue;

            set_input(term, inputIndex, replacement);
        }
    }
}
Exemple #10
0
    void tv_static_type_query(Type* type, StaticTypeQuery* query)
    {
        Term* subject = query->subject;
        Type* subjectType = query->subjectType;

        // If the type doesn't have a specific size, then accept any list.
        if (!list_type_has_specific_size(&type->parameter)) {
            if (is_list_based_type(subjectType))
                return query->succeed();
            else
                return query->fail();
        }

        caValue* expectedElementTypes = list_get_type_list_from_type(type);

        // Special case when looking at a call to list(); look at inputs instead of
        // looking at the result.
        if (subject && subject->function == FUNCS.list)
        {
            if (subject->numInputs() != circa_count(expectedElementTypes))
                return query->fail();

            for (int i=0; i < circa_count(expectedElementTypes); i++)
                if (!circa::term_output_always_satisfies_type(
                            subject->input(i), as_type(circa_index(expectedElementTypes, i))))
                    return query->fail();

            return query->succeed();
        }

        // Look at the subject's type.
        if (!list_type_has_specific_size(&subjectType->parameter))
            return query->fail();

        caValue* subjectElementTypes = list_get_type_list_from_type(subjectType);

        bool anyUnableToDetermine = false;

        for (int i=0; i < circa_count(expectedElementTypes); i++) {
            if (i >= circa_count(subjectElementTypes))
                return query->fail();

            StaticTypeQuery::Result result = run_static_type_query(
                    as_type(circa_index(expectedElementTypes,i)),
                    as_type(circa_index(subjectElementTypes,i)));

            // If any of these fail, then fail.
            if (result == StaticTypeQuery::FAIL)
                return query->fail();

            if (result == StaticTypeQuery::UNABLE_TO_DETERMINE)
                anyUnableToDetermine = true;
        }

        if (anyUnableToDetermine)
            return query->unableToDetermine();
        else
            return query->succeed();
    }
Exemple #11
0
void Term__input(VM* vm)
{
    Term* t = as_term_ref(vm->input(0));
    if (t == NULL)
        return vm->throw_str("NULL term");
    int index = vm->input(1)->as_i();
    if (index >= t->numInputs())
        set_term_ref(vm->output(), NULL);
    else
        set_term_ref(vm->output(), t->input(index));
}
Exemple #12
0
void Term__inputs(VM* vm)
{
    Term* t = as_term_ref(vm->input(0));
    if (t == NULL)
        return vm->throw_str("NULL term");

    Value* output = vm->output();
    circa_set_list(output, t->numInputs());

    for (int i=0; i < t->numInputs(); i++)
        set_term_ref(circa_index(output, i), t->input(i));
}
void Term__inputs(caStack* stack)
{
    Term* t = as_term_ref(circa_input(stack, 0));
    if (t == NULL)
        return circa_output_error(stack, "NULL reference");

    caValue* output = circa_output(stack, 0);
    circa_set_list(output, t->numInputs());

    for (int i=0; i < t->numInputs(); i++)
        set_term_ref(circa_index(output, i), t->input(i));
}
Exemple #14
0
Term* statically_infer_length_func(Block* block, Term* term)
{
    Term* input = term->input(0);
    if (input->function == FUNCS.copy)
        return statically_infer_length_func(block, input->input(0));

    if (input->function == FUNCS.list)
        return create_int(block, input->numInputs());

    if (input->function == FUNCS.list_append) {
        Term* leftLength = apply(block, FUNCS.length, TermList(input->input(0)));
        return apply(block, FUNCS.add, TermList(
                    statically_infer_length_func(block, leftLength),
                    create_int(block, 1)));
    }

    // Give up
    std::cout << "statically_infer_length_func didn't understand: "
        << input->function->name << std::endl;
    return create_string(block, "unknown");
}
Exemple #15
0
Term* statically_infer_length_func(Branch* branch, Term* term)
{
    Term* input = term->input(0);
    if (input->function == FUNCS.copy)
        return statically_infer_length_func(branch, input->input(0));

    if (input->function == FUNCS.list)
        return create_int(branch, input->numInputs());

    if (input->function == LIST_APPEND_FUNC) {
        Term* leftLength = apply(branch, FUNCS.length, TermList(input->input(0)));
        return apply(branch, FUNCS.add, TermList(
                    statically_infer_length_func(branch, leftLength),
                    create_int(branch, 1)));
    }

    // Give up
    std::cout << "statically_infer_length_func didn't understand: "
        << input->function->name << std::endl;
    return create_symbol_value(branch, name_Unknown);
}
void Term__input(caStack* stack)
{
    Term* t = as_term_ref(circa_input(stack, 0));
    if (t == NULL) {
        circa_output_error(stack, "NULL reference");
        return;
    }
    int index = circa_int_input(stack, 1);
    if (index >= t->numInputs())
        set_term_ref(circa_output(stack, 0), NULL);
    else
        set_term_ref(circa_output(stack, 0), t->input(index));
}
Exemple #17
0
Term* loop_find_iterator_advance(Block* block)
{
    Term* iterator = loop_find_iterator(block);
    for (int i=0; i < block->length(); i++) {
        Term* term = block->get(i);
        if (term->input(0) != iterator)
            continue;
        Value* methodName = term->getProp(s_method_name);
        if (methodName && string_equals(methodName, "advance"))
            return term;
    }
    return NULL;
}
Exemple #18
0
void Term__trace_dependents(VM* vm)
{
    Term* term = as_term_ref(vm->input(0));
    Block* untilBlock = as_block(vm->input(1));

    Value* out = vm->output();
    set_list(out, 0);
    std::set<Term*> included;

    UpwardIterator upwardIterator(term);
    upwardIterator.stopAt(untilBlock);

    // Look at starting term, because UpwardIterator doesn't yield starting term.
    // TODO: Should fix UpwardIterator
    for (int i=0; i < term->numInputs(); i++) {
        Term* input = term->input(i);
        if (input != NULL) {
            set_term_ref(list_append(out), input);
            included.insert(input);
        }
    }

    for (; upwardIterator.unfinished(); upwardIterator.advance()) {
        Term* current = upwardIterator.current();
        if (current == term || included.find(current) != included.end()) {

            for (int i=0; i < current->numInputs(); i++) {
                Term* input = current->input(i);
                if (input != NULL) {
                    set_term_ref(list_append(out), input);
                    included.insert(input);
                }
            }
        }
    }

    // Order results in the same order as the code.
    list_reverse(out);
}
Exemple #19
0
void block_update_pack_state_calls(Block* block)
{
    if (block->stateType == NULL) {
        // No state type, make sure there's no pack_state call.
        // TODO: Handle this case properly (should search and destroy an existing pack_state call)
        return;
    }

    int stateOutputIndex = block->length() - 1 - find_state_output(block)->index;

    for (int i=0; i < block->length(); i++) {
        Term* term = block->get(i);
        if (term == NULL)
            continue;

        if (term->function == FUNCS.pack_state) {
            // Update the inputs for this pack_state call
            TermList inputs;
            list_inputs_to_pack_state(block, i, &inputs);
            set_inputs(term, inputs);
        }

        else if (should_have_preceeding_pack_state(term)) {
            // Check if we need to insert a pack_state call
            Term* existing = term->input(stateOutputIndex);

            if (existing == NULL || existing->function != FUNCS.pack_state) {
                TermList inputs;
                list_inputs_to_pack_state(block, i, &inputs);
                if (inputs.length() != 0) {
                    Term* pack_state = apply(block, FUNCS.pack_state, inputs);
                    move_before(pack_state, term);

                    // Only set as an input for a non-minor block.
                    if (term->nestedContents == NULL || !is_minor_block(term->nestedContents)) {
                        set_input(term, stateOutputIndex, pack_state);
                        set_input_hidden(term, stateOutputIndex, true);
                        set_input_implicit(term, stateOutputIndex, true);
                    }

                    // Advance i to compensate for the term just added
                    i++;
                }
            }
        }
    }
}
Exemple #20
0
    void formatSource(caValue* source, Term* term)
    {
        format_name_binding(source, term);

        Block* contents = nested_contents(term);

        int index = 0;
        while (contents->get(index)->function == FUNCS.input)
            index++;

        bool firstCase = true;

        for (; index < contents->length(); index++) {
            Term* caseTerm = contents->get(index);

            if (caseTerm->function != FUNCS.case_func)
                break;

            if (is_hidden(caseTerm))
                continue;

            append_phrase(source,
                    caseTerm->stringProp("syntax:preWhitespace", ""),
                    caseTerm, tok_Whitespace);

            if (firstCase) {
                append_phrase(source, "if ", caseTerm, sym_Keyword);
                format_source_for_input(source, caseTerm, 0);
                firstCase = false;
            } else if (caseTerm->input(0) != NULL) {
                append_phrase(source, "elif ", caseTerm, sym_Keyword);
                format_source_for_input(source, caseTerm, 0);
            }
            else
                append_phrase(source, "else", caseTerm, sym_None);

            // whitespace following the if/elif/else
            append_phrase(source,
                    caseTerm->stringProp("syntax:lineEnding", ""),
                    caseTerm, tok_Whitespace);

            format_block_source(source, nested_contents(caseTerm), caseTerm);
        }
    }
Exemple #21
0
void branch_update_existing_pack_state_calls(Branch* branch)
{
    if (branch->stateType == NULL) {
        // No state type, make sure there's no pack_state call.
        // TODO: Handle this case properly (should search and destroy an existing pack_state call)
        return;
    }

    int stateOutputIndex = branch->length() - 1 - find_state_output(branch)->index;

    for (int i=0; i < branch->length(); i++) {
        Term* term = branch->get(i);
        if (term == NULL)
            continue;

        if (term->function == FUNCS.pack_state) {
            // Update the inputs for this pack_state call
            TermList inputs;
            get_list_of_state_outputs(branch, i, &inputs);

            set_inputs(term, inputs);
        }

        if (term->function == FUNCS.exit_point) {
            // Check if we need to insert a pack_state call
            Term* existing = term->input(stateOutputIndex);

            if (existing == NULL || existing->function != FUNCS.pack_state) {
                TermList inputs;
                get_list_of_state_outputs(branch, i, &inputs);
                if (inputs.length() != 0) {
                    Term* pack_state = apply(branch, FUNCS.pack_state, inputs);
                    move_before(pack_state, term);
                    set_input(term, stateOutputIndex + 1, pack_state);

                    // Advance i to compensate for the term just added
                    i++;
                }
            }
        }
    }
}
Exemple #22
0
Term* write_selector_for_accessor_chain(Branch* branch, TermList* chain)
{
    TermList selectorInputs;

    // Skip index 0 - this is the head term.
    
    for (int i=1; i < chain->length(); i++) {
        Term* term = chain->get(i);

        if (term->function == FUNCS.get_index
                || term->function == FUNCS.get_field) {

            selectorInputs.append(term->input(1));

        } else if (is_accessor_function(term)) {
            Term* element = create_string(branch, term->stringProp("syntax:functionName", ""));
            selectorInputs.append(element);
        }
    }

    return apply(branch, FUNCS.selector, selectorInputs);
}
Exemple #23
0
bool branch_state_type_is_out_of_date(Branch* branch)
{
    // Alloc an array that tracks, for each field in the existing stateType,
    // whether we have found a corresponding term for that field.
    bool* typeFieldFound = NULL;
    int existingFieldCount = 0;

    if (branch->stateType != NULL) {
        existingFieldCount = compound_type_get_field_count(branch->stateType);
        size_t size = sizeof(bool) * existingFieldCount;
        typeFieldFound = (bool*) malloc(size);
        memset(typeFieldFound, 0, size);
    }
    
    // Walk through every term and check whether every unpack_state call is already
    // mentioned in the state type.
    for (int i=0; i < branch->length(); i++) {
        Term* term = branch->get(i);
        if (term == NULL)
            continue;

        if (term->function != FUNCS.unpack_state)
            continue;

        // Found an unpack_state call
        Term* identifyingTerm = term->input(1);

        // If the branch doesn't yet have a stateType then that's an update.
        if (branch->stateType == NULL)
            goto return_true;

        // Look for the field name
        int fieldIndex = list_find_field_index_by_name(branch->stateType,
            unique_name(identifyingTerm));

        // If the name isn't found then that's an update
        if (fieldIndex == -1)
            goto return_true;

        // If the type doesn't match then that's an update
        if (compound_type_get_field_type(branch->stateType, fieldIndex)
                != declared_type(term))
            goto return_true;

        // Record this field index as 'found'
        typeFieldFound[fieldIndex] = true;
    }

    // If there were any fields in the type that weren't found in the branch, then
    // that's an update.
    if (typeFieldFound != NULL) {
        for (int i=0; i < existingFieldCount; i++) {
            if (!typeFieldFound[i])
                goto return_true;
        }
    }

    // No reason to update, return false.
    free(typeFieldFound);
    return false;

return_true:
    free(typeFieldFound);
    return true;
}
Exemple #24
0
void for_loop_finish_iteration(Stack* stack, bool enableLoopOutput)
{
    INCREMENT_STAT(LoopFinishIteration);

    Frame* frame = top_frame(stack);
    Branch* contents = frame->branch;

    // Find list length
    caValue* listInput = get_frame_register(frame, 0);

    // Increment the loop index
    caValue* index = get_top_register(stack, for_loop_find_index(contents));
    set_int(index, as_int(index) + 1);

    // Preserve list output
    if (enableLoopOutput && frame->exitType != name_Discard) {
        caValue* outputIndex = get_frame_register(frame, for_loop_find_output_index(contents));

        Term* outputPlaceholder = get_output_placeholder(contents, 0);
        caValue* outputList = get_frame_register(frame, outputPlaceholder);
        caValue* outputValue = find_stack_value_for_term(stack, outputPlaceholder->input(0), 0);

        if (!is_list(outputList))
            set_list(outputList);
        list_touch(outputList);
        copy(outputValue, list_get(outputList, as_int(outputIndex)));

        INCREMENT_STAT(LoopWriteOutput);

        // Advance output index
        set_int(outputIndex, as_int(outputIndex) + 1);
    }

    // Check if we are finished
    if (as_int(index) >= list_length(listInput)
            || frame->exitType == name_Break
            || frame->exitType == name_Return) {

        // Possibly truncate output list, in case any elements were discarded.
        if (enableLoopOutput) {
            caValue* outputIndex = get_frame_register(frame, for_loop_find_output_index(contents));
            Term* outputPlaceholder = get_output_placeholder(contents, 0);
            caValue* outputList = get_frame_register(frame, outputPlaceholder);
            list_resize(outputList, as_int(outputIndex));
        } else {
            Term* outputPlaceholder = get_output_placeholder(contents, 0);
            caValue* outputList = get_frame_register(frame, outputPlaceholder);
            set_list(outputList, 0);
        }
        
        finish_frame(stack);
        return;
    }

    // If we're not finished yet, copy rebound outputs back to inputs.
    for (int i=1;; i++) {
        Term* input = get_input_placeholder(contents, i);
        if (input == NULL)
            break;
        Term* output = get_output_placeholder(contents, i);
        copy(get_frame_register(frame, output),
            get_frame_register(frame, input));

        INCREMENT_STAT(Copy_LoopCopyRebound);
    }

    // Return to start of loop body
    frame->pc = 0;
    frame->nextPc = 0;
    frame->exitType = name_None;
}
Exemple #25
0
void Block__output(VM* vm)
{
    Block* block = as_block(vm->input(0));
    Term* placeholder = get_output_placeholder(block, vm->input(1)->as_i());
    set_term_ref(vm->output(), placeholder->input(0));
}
Exemple #26
0
void static_type_func(caStack* stack)
{
    Term* caller = (Term*) circa_caller_term(stack);
    Term* input = caller->input(0);
    set_type(circa_output(stack, 0), input->type);
}