void file_source_read_file(Value* file_source, Value* name, Value* contents) { if (file_source_is_map(file_source)) { Value* entry = hashtable_get(file_source, name); if (entry == NULL) set_null(contents); else copy(list_get(entry, 1), contents); return; } else if (file_source_is_filesystem_backed(file_source)) { Value fullPath; Value* rootDir = list_get(file_source, 1); copy(rootDir, &fullPath); join_path(&fullPath, name); read_text_file(as_cstring(&fullPath), contents); return; } else if (file_source_is_tarball_backed(file_source)) { Value* tarball = list_get(file_source, 1); tar_read_file(tarball, as_cstring(name), contents); return; } internal_error("file_source_read_file: file_source type not recognized"); }
static bool find_module_file(const char* module_name, caValue* filenameOut) { Value module; set_string(&module, module_name); int count = list_length(&g_moduleSearchPaths); for (int i=0; i < count; i++) { // For each search path we'll check two places. // Look under searchPath/moduleName.ca Value searchPath; copy(g_moduleSearchPaths[i], &searchPath); circa_join_path(&searchPath, &module); string_append(&searchPath, ".ca"); if (circa_file_exists(as_cstring(&searchPath))) { swap(&searchPath, filenameOut); return true; } // Look under searchPath/moduleName/moduleName.ca copy(g_moduleSearchPaths[i], &searchPath); circa_join_path(&searchPath, &module); circa_join_path(&searchPath, &module); string_append(&searchPath, ".ca"); if (circa_file_exists(as_cstring(&searchPath))) { swap(&searchPath, filenameOut); return true; } } return false; }
void join_path(Value* left, Value* right) { const char* leftStr = as_cstring(left); const char* rightStr = as_cstring(right); int left_len = (int) strlen(leftStr); int right_len = (int) strlen(leftStr); if (string_equals(left, "") || string_equals(left, ".")) { copy(right, left); return; } if (string_equals(right, "")) return; int seperatorCount = 0; if (left_len > 0 && is_path_seperator(leftStr[left_len-1])) seperatorCount++; if (right_len > 0 && is_path_seperator(rightStr[0])) seperatorCount++; if (seperatorCount == 2) string_resize(left, left_len - 1); else if (seperatorCount == 0) string_append(left, "/"); string_append(left, right); }
void file_watch_trigger_actions(World* world, FileWatch* watch) { // Walk through each action and execute it. for (int i = 0; i < list_length(&watch->onChangeActions); i++) { caValue* action = list_get(&watch->onChangeActions, i); Name label = as_int(list_get(action, 0)); ca_assert(label != name_None); switch (label) { case name_NativePatch: { caValue* moduleName = list_get(action, 1); NativePatch* nativeModule = add_native_patch(world, as_cstring(moduleName)); native_patch_load_from_file(nativeModule, as_cstring(&watch->filename)); native_patch_finish_change(nativeModule); break; } case name_PatchBlock: { // Reload this code block. caValue* moduleName = list_get(action, 1); load_module_file(world, as_cstring(moduleName), as_cstring(&watch->filename)); break; } default: internal_error("unrecognized file watch action"); } } }
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 dynamic_method_call(caStack* stack) { INCREMENT_STAT(DynamicMethodCall); caValue* args = circa_input(stack, 0); caValue* object = circa_index(args, 0); // Lookup method Term* term = (Term*) circa_caller_term(stack); std::string functionName = term->stringProp("syntax:functionName", ""); // Find and dispatch method Term* method = find_method((Block*) circa_caller_block(stack), (Type*) circa_type_of(object), functionName.c_str()); // copy(object, circa_output(stack, 1)); if (method != NULL) { // Grab inputs before pop Value inputs; swap(args, &inputs); pop_frame(stack); push_frame_with_inputs(stack, function_contents(method), &inputs); return; } // Method not found. Raise error. std::string msg; msg += "Method "; msg += functionName; msg += " not found on type "; msg += as_cstring(&circa_type_of(object)->name); circa_output_error(stack, msg.c_str()); }
bool block_check_invariants_print_result(Block* block, Value* out) { circa::Value result; block_check_invariants(&result, block); if (list_length(&result) == 0) return true; string_append(out, list_length(&result)); string_append(out, " errors found in block "); string_append_ptr(out, block); string_append(out, "\n"); for (int i=0; i < list_length(&result); i++) { Value* error = list_get(&result,i); string_append(out, "["); string_append(out, as_int(list_get(error, 1))); string_append(out, "]"); string_append(out, as_cstring(list_get(error, 2))); string_append(out, "\n"); } string_append(out, "contents:\n"); print_block(block, out); return false; }
const char* term_get_string_input_prop(Term* term, int inputIndex, Symbol key, const char* defaultValue) { Value* value = term_get_input_property(term, inputIndex, key); if (value == NULL) return defaultValue; return as_cstring(value); }
void TokenStream::reset(Value* inputString) { _position = 0; tokens.clear(); set_value(&_sourceText, inputString); tokenize(as_cstring(&_sourceText), string_length(&_sourceText), &tokens); }
const char* Term::name() { if (!is_string(&nameValue)) return ""; return as_cstring(&nameValue); }
caValue* selector_advance(caValue* value, caValue* selectorElement, caValue* error) { if (is_int(selectorElement)) { int selectorIndex = as_int(selectorElement); if (!is_list(value)) { set_error_string(error, "Value is not indexable: "); string_append_quoted(error, value); return NULL; } if (selectorIndex >= list_length(value)) { set_error_string(error, "Index "); string_append(error, selectorIndex); string_append(error, " is out of range"); return NULL; } return get_index(value, selectorIndex); } else if (is_string(selectorElement)) { caValue* field = get_field(value, as_cstring(selectorElement)); if (field == NULL) { set_error_string(error, "Field not found: "); string_append(error, selectorElement); return NULL; } return field; } else { set_error_string(error, "Unrecognized selector element: "); string_append_quoted(error, selectorElement); return NULL; } }
Branch* load_module(const char* module_name, Term* loadCall) { Branch* existing = find_loaded_module(module_name); if (existing != NULL) return existing; Value filename; bool found = find_module_file(module_name, &filename); if (!found) return NULL; Term* import = load_module_from_file(module_name, as_cstring(&filename))->owningTerm; // If a loadCall is provided, possibly move the new import to be before the loadCall. if (loadCall != NULL) { Term* callersModule = find_parent_term_in_branch(loadCall, import->owningBranch); if (callersModule != NULL && (import->index > callersModule->index)) move_before(import, callersModule); } // If the module has static errors, print them now. print_static_errors_formatted(nested_contents(import)); return nested_contents(import); }
void parse_string_as_argument_list(caValue* str, List* output) { // Read the tokens as a space-seperated list of strings. // TODO is to be more smart about word boundaries: spaces inside // quotes or parentheses shouldn't break apart items. TokenStream tokens; tokens.reset(as_cstring(str)); Value itemInProgress; set_string(&itemInProgress, ""); while (!tokens.finished()) { if (tokens.nextIs(tok_Whitespace)) { if (!equals_string(&itemInProgress, "")) { copy(&itemInProgress, list_append(output)); set_string(&itemInProgress, ""); } } else { string_append(&itemInProgress, tokens.nextStr().c_str()); } tokens.consume(); } if (!equals_string(&itemInProgress, "")) { copy(&itemInProgress, list_append(output)); set_string(&itemInProgress, ""); } }
void load_script(Block* block, const char* filename) { // Store the filename set_string(block_insert_property(block, s_filename), filename); // Read the text file circa::Value contents; circa_read_file(block->world, filename, &contents); if (is_null(&contents)) { Value msg; set_string(&msg, "File not found: "); string_append(&msg, filename); Term* term = create_string(block, as_cstring(&msg)); apply(block, FUNCS.error, TermList(term)); return; } parse(block, parse_statement_list, &contents); // Make sure the block has a primary output. if (get_output_placeholder(block, 0) == NULL) append_output_placeholder(block, NULL); update_static_error_list(block); return; }
void set_symbol_from_string(caValue* val, caValue* str) { // Find this name as an existing builtin symbol. int foundBuiltin = builtin_symbol_from_string(as_cstring(str)); if (foundBuiltin != -1) { set_symbol(val, foundBuiltin); return; } // Find this name as an existing runtime symbol. caValue* foundRuntime = hashtable_get(g_runtimeSymbolMap, str); if (foundRuntime != NULL) { copy(foundRuntime, val); return; } // Create a new runtime symbol. caValue* newRuntime = hashtable_insert(g_runtimeSymbolMap, str); int index = g_nextRuntimeSymbol++; set_symbol(newRuntime, index); set_symbol(val, index); list_resize(g_runtimeSymbolTable, index+1); set_value(list_get(g_runtimeSymbolTable, index), str); }
void dll_loading_check_for_patches_on_loaded_branch(Branch* branch) { for (BranchIteratorFlat it(branch); it.unfinished(); it.advance()) { if (it.current()->function == FUNCS.dll_patch) { Term* caller = it.current(); // Find the DLL. String filename; find_dll_for_script(branch, &filename); if (!is_string(&filename)) { mark_static_error(caller, "Couldn't find DLL"); continue; } Value error; patch_with_dll(as_cstring(&filename), branch, &error); if (!is_null(&error)) { std::cout << as_string(&error) << std::endl; mark_static_error(caller, &error); continue; } } } }
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); }
void run_repl_stdin(World* world) { Stack* stack = alloc_stack(world); repl_start(stack); printf("Started REPL, type /help for reference.\n"); while (true) { Value input; // Get next line if (!circa_get_line(&input)) break; // Before doing any work, process any pending file changes. file_watch_check_all(world); Value output; repl_run_line(stack, &input, &output); for (int i=0; i < list_length(&output); i++) std::cout << as_cstring(list_get(&output, i)) << std::endl; // Check if we've finished. if (top_frame(stack) == NULL) return; } }
void run_generate_cpp(caValue* args) { if (list_length(args) < 2) { std::cout << "Expected 2 arguments"; return; } const char* source_file = as_cstring(list_get(args, 0)); const char* output_file = as_cstring(list_get(args, 1)); std::cout << "Loading source from: " << source_file << std::endl; std::cout << "Will write to: " << output_file << std::endl; Block block; load_script(&block, source_file); write_program_to_file(&block, output_file); }
int string_find_char(caValue* s, int start, char c) { const char* cstr = as_cstring(s); for (int i=start; cstr[i] != 0; i++) if (cstr[i] == c) return i; return -1; }
Type* create_typed_unsized_list_type(Type* elementType) { Type* type = create_type(); list_t::setup_type(type); set_type(&type->parameter, elementType); std::string name = std::string("List<") + as_cstring(&elementType->name) + ">"; set_string(&type->name, name.c_str()); return type; }
int string_find_char_from_end(caValue* s, char c) { const char* cstr = as_cstring(s); for (int i= (int) strlen(cstr) - 1; i >= 0; i--) if (cstr[i] == c) return i; return -1; }
std::string TokenStream::consumeStr(int match) { Value next; getNextStr(&next); std::string out = as_cstring(&next); consume(match); return out; }
void test_assert_function(Block* block, int line, const char* file) { Value str; if (!block_check_invariants_print_result(block, &str)) { std::cout << as_cstring(&str) << std::endl; std::cout << "Block failed invariant check in " << file << ", line " << line << std::endl; declare_current_test_failed(); } Value errors; check_for_static_errors(&errors, block); if (!errors.isEmpty()) { std::cout << "Block has static errors at " << file << ", line " << line << std::endl; print_static_errors_formatted(&errors, &str); std::cout << as_cstring(&str) << std::endl; declare_current_test_failed(); } }
void module_possibly_patch_new_function(World* world, Block* function) { NativePatchWorld* moduleWorld = world->nativePatchWorld; Value globalName; get_global_name(function, &globalName); // No global name: no patch. if (!is_string(&globalName)) return; // Lookup in the global table. caValue* patchEntry = hashtable_get(&moduleWorld->everyPatchedFunction, &globalName); if (patchEntry == NULL) { // No patch for this function. return; } caValue* nativeModuleName = list_get(patchEntry, 0); caValue* functionName = list_get(patchEntry, 1); // Found a patch; apply it. NativePatch* module = get_existing_native_patch(world, as_cstring(nativeModuleName)); if (module == NULL) { std::cout << "in module_possibly_patch_new_function, couldn't find module: " << as_cstring(nativeModuleName) << std::endl; return; } std::map<std::string, EvaluateFunc>::const_iterator it; it = module->patches.find(as_cstring(functionName)); if (it == module->patches.end()) { std::cout << "in module_possibly_patch_new_function, couldn't find function: " << as_cstring(functionName) << std::endl; return; } EvaluateFunc evaluateFunc = it->second; install_function(function->owningTerm, evaluateFunc); }
int get_hash_value(caValue* value) { Type::HashFunc f = value->value_type->hashFunc; if (f == NULL) { std::string msg; msg += std::string("No hash function for type ") + as_cstring(&value->value_type->name); internal_error(msg); } return f(value); }
bool string_starts_with(caValue* s, const char* beginning) { const char* left = as_cstring(s); for (int i=0;; i++) { if (beginning[i] == 0) return true; if (left[i] != beginning[i]) return false; } }
void Type__property(caStack* stack) { Type* type = as_type(circa_input(stack, 0)); const char* str = as_cstring(circa_input(stack, 1)); caValue* prop = get_type_property(type, str); if (prop == NULL) set_null(circa_output(stack, 0)); else copy(prop, circa_output(stack, 0)); }
bool file_source_does_file_exist(Value* file_source, Value* name) { if (file_source_is_map(file_source)) { return hashtable_get(file_source, name) != NULL; } else if (file_source_is_filesystem_backed(file_source)) { Value fullPath; Value* rootDir = list_get(file_source, 1); copy(rootDir, &fullPath); join_path(&fullPath, name); return file_exists(as_cstring(&fullPath)); } else if (file_source_is_tarball_backed(file_source)) { Value* tarball = list_get(file_source, 1); return tar_file_exists(tarball, as_cstring(name)); } internal_error("file_source_does_file_exist: file_source type not recognized"); return false; }
static bool file_watch_check_for_update(FileWatch* watch) { int latestMtime = file_get_mtime(as_cstring(&watch->filename)); if (latestMtime != watch->lastObservedMtime) { watch->lastObservedMtime = latestMtime; return true; } return false; }