void pre_erase_term(Term* term) { // If this term declares a Type, then clear the Type.declaringTerm pointer, // before it becomes invalid. if (is_type(term) && as_type(term_value(term))->declaringTerm == term) as_type(term_value(term))->declaringTerm = NULL; }
Type* get_field_specializeType(Term* caller) { Type* head = caller->input(0)->type; for (int nameIndex=1; nameIndex < caller->numInputs(); nameIndex++) { // Abort if input type is not correct if (!is_string(term_value(caller->input(1)))) return TYPES.any; if (!is_list_based_type(head)) return TYPES.any; Value* name = term_value(caller->input(1)); int fieldIndex = list_find_field_index_by_name(head, name); if (fieldIndex == -1) return TYPES.any; head = as_type(get_index(list_get_type_list_from_type(head),fieldIndex)); } return head; }
void Term__asint(VM* vm) { Term* t = as_term_ref(vm->input(0)); if (t == NULL) return vm->throw_str("NULL term"); if (!is_int(term_value(t))) return vm->throw_str("Not an int"); set_int(vm->output(), as_int(term_value(t))); }
void find_name() { Block block; block.compile("a = 1"); block.compile("namespace ns { a = 2; b = 3; } "); test_equals(term_value(find_name(&block, "a")), "1"); test_equals(term_value(find_name(&block, "ns:a")), "2"); test_equals(term_value(find_name(&block, "ns:b")), "3"); }
void test_block_as_assertions_list(Block* block, std::string const& contextStr) { if (has_static_errors(block)) { std::cout << "Static error " << contextStr << ":" << std::endl; print_static_errors_formatted(block, std::cout); declare_current_test_failed(); return; } std::stringstream checkInvariantsOutput; if (!block_check_invariants_print_result(block, checkInvariantsOutput)) { std::cout << "Failed invariant " << contextStr << std::endl; std::cout << checkInvariantsOutput.str() << std::endl; declare_current_test_failed(); return; } Stack context; evaluate_block(&context, block); if (context.errorOccurred) { std::cout << "Runtime error " << contextStr << std::endl; print_error_stack(&context, std::cout); declare_current_test_failed(); return; } int boolean_statements_found = 0; for (int i=0; i < block->length(); i++) { Term* term = block->get(i); if (!is_statement(term)) continue; if (!is_bool(term_value(term))) continue; boolean_statements_found++; if (!as_bool(term_value(term))) { std::cout << "Assertion failed " << contextStr << std::endl; std::cout << "failed: " << get_term_source_text(term) << std::endl; declare_current_test_failed(); return; } } if (boolean_statements_found == 0) { std::cout << "No boolean statements found " << contextStr << std::endl; declare_current_test_failed(); return; } }
void Term__asint(caStack* stack) { Term* t = as_term_ref(circa_input(stack, 0)); if (t == NULL) { circa_output_error(stack, "NULL reference"); return; } if (!is_int(term_value(t))) { circa_output_error(stack, "Not an int"); return; } set_int(circa_output(stack, 0), as_int(term_value(t))); }
void nested_name_match() { Block block; Term* a = block.compile("a = { b = { c = 4 }}"); block.compile("a2 = { b2 = 5 }"); test_assert(a == find_term_from_path_expression(&block, "a")); Term* c = find_term_from_path_expression(&block, "a/b/c"); Term* b2 = find_term_from_path_expression(&block, "a2/b2"); test_assert(c != NULL); test_assert(b2 != NULL); test_equals(term_value(c), "4"); test_equals(term_value(b2), "5"); }
void simple_name_match() { Block block; block.compile("a = 1; b = 2; c = 3"); Term* a = find_term_from_path_expression(&block, "a"); Term* b = find_term_from_path_expression(&block, "b"); Term* c = find_term_from_path_expression(&block, "c"); test_assert(a != NULL); test_assert(b != NULL); test_assert(c != NULL); test_equals(term_value(a), "1"); test_equals(term_value(b), "2"); test_equals(term_value(c), "3"); }
void Term__to_string(caStack* stack) { Term* t = as_term_ref(circa_input(stack, 0)); if (t == NULL) return circa_output_error(stack, "NULL reference"); set_string(circa_output(stack, 0), circa::to_string(term_value(t))); }
void Term__tweak(caStack* stack) { Term* t = as_term_ref(circa_input(stack, 0)); if (t == NULL) return circa_output_error(stack, "NULL reference"); int steps = tweak_round(to_float(circa_input(stack, 1))); caValue* val = term_value(t); if (steps == 0) return; if (is_float(val)) { float step = get_step(t); // Do the math like this so that rounding errors are not accumulated float new_value = (tweak_round(as_float(val) / step) + steps) * step; set_float(val, new_value); } else if (is_int(val)) set_int(val, as_int(val) + steps); else circa_output_error(stack, "Ref is not an int or number"); }
void erase_term(Term* term) { pre_erase_term(term); set_null(term_value(term)); set_inputs(term, TermList()); change_function(term, NULL); term->type = NULL; remove_nested_contents(term); // for each user, clear that user's input list of this term remove_from_any_user_lists(term); clear_from_dependencies_of_users(term); if (term->owningBlock != NULL) { // remove name binding if necessary term->owningBlock->removeNameBinding(term); // index may be invalid if something bad has happened ca_assert(term->index < term->owningBlock->length()); term->owningBlock->_terms.setAt(term->index, NULL); term->owningBlock = NULL; term->index = -1; } dealloc_term(term); }
Type* Type_cast_specializeType(Term* caller) { if (is_value(caller->input(0)) && is_type(caller->input(0))) return as_type(term_value(caller->input(0))); return NULL; }
void Term__to_string(VM* vm) { Term* t = as_term_ref(vm->input(0)); if (t == NULL) return vm->throw_str("NULL term"); circa::to_string(term_value(t), vm->output()); }
std::string to_string(Term* term) { caValue* value = term_value(term); bool valueHasAlpha = as_float(list_get(value,3)) < 1.0; int specifiedDigits = term->intProp("syntax:colorFormat", 6); int digitsPerChannel = (specifiedDigits == 6 || specifiedDigits == 8) ? 2 : 1; bool specifyAlpha = valueHasAlpha || (specifiedDigits == 4 || specifiedDigits == 8); std::stringstream out; out << "#"; for (int c=0; c < 4; c++) { if (c == 3 && !specifyAlpha) break; double channel = std::min((double) as_float(list_get(value, c)), 1.0); if (digitsPerChannel == 1) out << number_to_hex_digit(int(channel * 15.0)); else { int mod_255 = int(channel * 255.0); out << number_to_hex_digit(mod_255 / 0x10); out << number_to_hex_digit(mod_255 % 0x10); } } return out.str(); }
void unload_dll(const char* filename) { LoadedDllMap::iterator it = g_loadedDlls.find(filename); if (it == g_loadedDlls.end()) return; Dll* dll = it->second; g_loadedDlls.erase(it); // Track down anyone using this dll, and blank out those function pointers for (int i=0; i < dll->affectedTerms.length(); i++) { Term* ref = dll->affectedTerms[i]; if (!is_function(ref)) continue; Function* attrs = as_function(term_value(ref)); if (dll->loadedFunctions.find((void*) attrs->evaluate) != dll->loadedFunctions.end()) attrs->evaluate = NULL; } // Platform specific #ifdef WINDOWS // TODO #else dlclose(dll->module); #endif delete dll; }
void Term__asfloat(VM* vm) { Term* t = as_term_ref(vm->input(0)); if (t == NULL) return vm->throw_str("NULL term"); set_float(vm->output(), to_float(term_value(t))); }
void string_format_source(caValue* source, Term* term) { if (term->hasProperty("syntax:originalString")) { append_phrase(source, term->stringProp("syntax:originalString", ""), term, tok_String); return; } std::string quoteType = term->stringProp("syntax:quoteType", "'"); std::string result; if (quoteType == "<") result = "<<<" + as_string(term_value(term)) + ">>>"; else result = quoteType + as_cstring(term_value(term)) + quoteType; append_phrase(source, result, term, tok_String); }
void recursive_wildcard_match() { Block block; block.compile("a = 1"); block.compile("b = { c = 2 }"); block.compile("d = { e = { f = 3 } }"); Term* a = find_term_from_path_expression(&block, "**/a"); Term* c = find_term_from_path_expression(&block, "**/c"); Term* f = find_term_from_path_expression(&block, "** / f"); test_assert(a != NULL); test_assert(c != NULL); test_assert(f != NULL); test_equals(term_value(a), "1"); test_equals(term_value(c), "2"); test_equals(term_value(f), "3"); }
void Term__set_value(VM* vm) { Term* target = as_term_ref(vm->input(0)); if (target == NULL) return vm->throw_str("NULL term"); copy(vm->input(1), term_value(target)); }
void format_source(caValue* source, Term* term) { std::stringstream strm; if (term->stringProp("syntax:integerFormat", "dec") == "hex") strm << "0x" << std::hex; strm << as_int(term_value(term)); append_phrase(source, strm.str(), term, tok_Integer); }
void selector_format_source(caValue* source, Term* term) { // Append subscripts for each selector element for (int i=0; i < term->numInputs(); i++) { Term* input = term->input(i); if (is_value(input) && is_string(term_value(input))) { append_phrase(source, ".", input, tok_Dot); append_phrase(source, as_string(term_value(input)), input, tok_Identifier); } else { append_phrase(source, "[", term, tok_LBracket); format_source_for_input(source, term, i, "", ""); append_phrase(source, "]", term, tok_LBracket); } } }
Block* find_module_for_require_statement(Term* term) { if (term->input(0) == NULL) return NULL; Value* moduleName = term_value(term->input(0)); return find_module(term->owningBlock, moduleName); }
void Term__asfloat(caStack* stack) { Term* t = as_term_ref(circa_input(stack, 0)); if (t == NULL) { circa_output_error(stack, "NULL reference"); return; } set_float(circa_output(stack, 0), to_float(term_value(t))); }
void wildcard_nested_match() { Block block; block.compile("a = { b = { c = 5 } }"); block.compile("a = { b2 = { d = 6 } }"); Term* d = find_term_from_path_expression(&block, "a/*/d"); test_assert(d != NULL); test_equals(term_value(d), "6"); }
void Term__value(caStack* stack) { Term* target = as_term_ref(circa_input(stack, 0)); if (target == NULL) { circa_output_error(stack, "NULL reference"); return; } copy(term_value(target), circa_output(stack, 0)); }
void test_assert_function(Term* term, int line, const char* file) { if (term == NULL) { std::cout << "NULL term in " << file << ", line " << line << std::endl; declare_current_test_failed(); return; } if (has_static_error(term)) { std::cout << "Compile error on term " << global_id(term) << std::endl; print_static_error(term, std::cout); std::cout << std::endl; std::cout << "Occurred in " << file << ", line " << line << std::endl; declare_current_test_failed(); } if (is_bool(term_value(term)) && !as_bool(term_value(term))) { std::cout << "Assertion failed: " << get_term_source_text(term) << std::endl; std::cout << "Occurred in " << file << ", line " << line << std::endl; declare_current_test_failed(); } }
void write_term_value(SourceWriter* writer, Term* term) { caValue* val = term_value(term); if (is_int(val)) { writer->write(as_cstring(val)); } else if (is_float(val)) { writer->write(as_cstring(val)); } else if (is_string(val)) { writer->write("\""); writer->write(as_cstring(val)); writer->write("\""); } }
void statically_infer_result(Term* term, caValue* result) { Branch scratch; Term* resultTerm = statically_infer_result(&scratch, term); if (is_value(resultTerm)) copy(term_value(resultTerm), result); else { Stack context; evaluate_minimum(&context, resultTerm, result); } }
void Term__assign(caStack* stack) { Term* target = as_term_ref(circa_input(stack, 0)); if (target == NULL) { circa_output_error(stack, "NULL reference"); return; } caValue* source = circa_input(stack, 1); circa::copy(source, term_value(target)); // Probably should update term->type at this point. }
void Term__assign(VM* vm) { Term* target = as_term_ref(vm->input(0)); if (target == NULL) { return vm->throw_str("NULL term"); return; } Value* source = vm->input(1); circa::copy(source, term_value(target)); // Probably should update term->type at this point. }