HempBool hemp_module_load( HempModule module ) { hemp_debug_call("loading module: %s\n", module->name); /* just in case we've been here before */ if (module->handle) { // hemp_debug_msg("module is already loaded: %s\n", module->name); return HEMP_TRUE; } else if (module->error) { // hemp_debug_msg("module has already failed: %s (%s)\n", module->name, module->error); return HEMP_FALSE; } module->handle = dlopen(module->name, RTLD_NOW|RTLD_GLOBAL); if (! module->handle) { // hemp_debug_msg("module failed: %s\n", module->name); return hemp_module_failed( module, "Failed to load %s module: %s", module->name, dlerror() ); } // hemp_debug_msg("loaded module: %s\n", module->name); module->loader = (HempLoader) dlsym(module->handle, HEMP_MODULE_LOADER); module->binder = (HempBinder) dlsym(module->handle, HEMP_MODULE_BINDER); /* customer loader can augment module and/or perform initialisation */ if (module->loader) { hemp_debug_call("calling module loader: %s", HEMP_MODULE_LOADER); if (! module->loader(module)) { return HEMP_FALSE; } } if (! module->binder) { return hemp_module_failed( module, "Missing %s() function in %s module", HEMP_MODULE_BINDER, module->name ); } // hemp_debug_msg("found plugin init: %p\n", module->plugin); return HEMP_TRUE; }
HempList hemp_parse_pairs( HEMP_PREFIX_ARGS ) { hemp_debug_call("hemp_parse_pairs()\n"); HempFragment expr; HempList exprs = hemp_list_new(); while (1) { /* skip whitespace and delimiters (commas) */ hemp_skip_delimiter(fragptr); // hemp_debug_msg("%s parse_prefix (prec: %d): %p\n", save->type->name, precedence, save->type->parse_pair); expr = hemp_parse_pair(fragptr, scope, precedence, HEMP_FALSE); /* if it's not a pairable expression then we're done */ if (! expr) { // hemp_debug_msg("expression does not yield pairs: %s (%p vs %p)\n", save->type->name, save, *fragptr); break; } // hemp_debug_msg("expression yields pairs: %s\n", expr->type->name); hemp_list_push(exprs, hemp_frag_val(expr)); } if (! exprs->length && ! force) { hemp_list_free(exprs); exprs = NULL; } return exprs; }
HempBool hemp_document_scan( HempDocument document ) { hemp_debug_call("hemp_document_scan(%p)\n", document); if (! document->dialect->scanner) hemp_fatal("No scanner defined for %s document\n", document->dialect->name); if (! document->source->text) hemp_source_read(document->source); document->scanptr = document->scantok = document->source->text; document->scanpos = 0; if (! document->scantags) document->scantags = hemp_stack_new(HEMP_SCANTAGS_SIZE); return document->dialect->scanner(document) ? HEMP_TRUE : HEMP_FALSE; // return hemp_action_run(document->scanner, document) // ? HEMP_TRUE // : HEMP_FALSE; }
HempValue hemp_document_data( HempDocument document, HempContext context ) { hemp_debug_call("hemp_document_data(%p)\n", document); HempBool my_context = HEMP_FALSE; HempFragment root = hemp_document_tree(document); HempValue values; HempList results; if (! root) hemp_fatal("document does not have a root element"); if (! context) { my_context = HEMP_TRUE; context = hemp_context_new(document->hemp); } values = root->type->values(hemp_frag_val(root), context, HempNothing); results = hemp_val_list(values); if (my_context) hemp_context_free(context); if (results->length > 1) { return values; } else if (results->length == 1) { return hemp_list_item(results, 0); } else { return HempEmpty; } }
HempText hemp_document_process( HempDocument document, HempContext context, HempText output ) { hemp_debug_call("hemp_document_process(%p)\n", document); HempBool my_context = HEMP_FALSE; HempFragment root = hemp_document_tree(document); if (! context) { my_context = HEMP_TRUE; context = hemp_context_new(document->hemp); } if (! root) hemp_fatal("document does not have a root element"); if (! output) output = hemp_text_new(); root->type->text(hemp_frag_val(root), context, hemp_text_val(output)); // HEMP_CATCH_ALL; // hemp_fatal("Error processing document: %s", hemp->error->message); // HEMP_END; if (my_context) hemp_context_free(context); return output; }
HempText hemp_document_render( HempDocument document, HempContext context ) { hemp_debug_call("hemp_document_render(%p)\n", document); return hemp_document_process(document, context, NULL); }
void hemp_scheme_file_cleaner( HempSource source ) { if (source->text) { hemp_debug_call("cleaning file source: %s\n%s\n", source->name, source->text); hemp_mem_free(source->text); } }
HempFragment hemp_document_tokens( HempDocument document ) { hemp_debug_call("hemp_document_tokens(%p)\n", document); if (! document->fragments->head) hemp_document_scan(document); return document->fragments->head; }
HempFragment hemp_document_tree( HempDocument document ) { hemp_debug_call("hemp_document_tree(%p)\n", document); if (! document->tree) hemp_document_compile(document); return document->tree; }
HempList hemp_list_init( HempList list ) { HEMP_INSTANCE(list); hemp_debug_call("hemp_list_init(%p)\n", list); list->items = NULL; list->length = 0; list->capacity = 0; list->cleaner = NULL; return list; }
void hemp_list_release( HempList list ) { hemp_debug_call("hemp_list_release(%p)\n", list); if (list->items) { if (list->cleaner) { hemp_list_each(list, list->cleaner); } hemp_mem_free(list->items); list->items = NULL; } }
HempBool hemp_document_compile( HempDocument document ) { hemp_debug_call("hemp_document_compile(%p)\n", document); document->tree = hemp_fragment_parse( hemp_document_tokens(document), document->scope ); // TODO: proper error handling return HEMP_TRUE; }
HempBool hemp_list_index( HempContext context, HempValue key, HempInt *index ) { hemp_debug_call("hemp_list_index()\n"); HempBool found = HEMP_FALSE; if (hemp_is_integer(key)) { // hemp_debug("got integer key\n"); *index = hemp_val_int(key); found = HEMP_TRUE; } else { HempText ktext; HempBool kmine = HEMP_FALSE; if (hemp_is_text(key)) { // hemp_debug("got text key\n"); ktext = hemp_val_text(key); } else { /* otherwise we have to convert the key to text */ /* TODO: must be a better way to check for numeric conversion without throwing an error? */ // hemp_debug("creating text key\n"); ktext = hemp_text_new_size(16); kmine = HEMP_TRUE; hemp_onto_text(key, context, hemp_text_val(ktext)); } // hemp_debug("list text key: %s\n", ktext->string); if (hemp_string_intlike(ktext->string)) { // hemp_debug("got numlike string\n"); *index = hemp_val_int( hemp_type_string_integer( hemp_str_val(ktext->string), context) ); found = HEMP_TRUE; } else { // hemp_debug("text index is not numlike: %s\n", ktext->string); } if (kmine) hemp_text_free(ktext); } return found; }
HempList hemp_parse_exprs( HEMP_PREFIX_ARGS ) { hemp_debug_call("hemp_parse_exprs( precedence => %d )\n", precedence); HempFragment expr; HempList exprs = hemp_list_new(); // hemp_debug_msg("hemp_parse_exprs() LIST: %p\n", exprs); while (1) { /* skip whitespace, delimiters (commas) and separators (semi-colons) */ hemp_skip_separator(fragptr); /* ask the next token to return an expression */ hemp_debug_parse("%s parse_prefix: %p\n", (*fragptr)->type->name, (*fragptr)->type->parse_prefix); expr = hemp_parse_prefix(fragptr, scope, precedence, HEMP_FALSE); /* if it's not an expression (e.g. a terminator) then we're done */ if (! expr) break; hemp_debug_parse("expr: %s\n", expr->type->name); hemp_list_push(exprs, hemp_frag_val(expr)); } /* element should be EOF or we hit a duff token */ if (hemp_at_eof(fragptr)) { hemp_debug_parse("%sReached EOF\n%s\n", HEMP_ANSI_GREEN, HEMP_ANSI_RESET); } else { hemp_debug_parse("%sNot an expression: %s:%s\n", HEMP_ANSI_RED, (*fragptr)->type->name, HEMP_ANSI_RESET); } // hemp_debug("n expressions: %d\n", exprs->length); if (! exprs->length && ! force) { hemp_list_free(exprs); exprs = NULL; } #if HEMP_DEBUG & HEMP_DEBUG_PARSE hemp_fragment_dump_exprs(exprs); #endif return exprs; }
HempBool hemp_viewer_add_view( HempViewer viewer, HempString name, hemp_view_f view ) { hemp_debug_call("hemp_viewer_add_view(%s:%s => %p)\n", viewer->name, name, view); HempU16 id = hemp_namespace_id(name); hemp_debug("%s ID: %d\n", name, id); if (id >= viewer->size) hemp_viewer_resize(viewer, id); if (viewer->view[id]) { hemp_debug("already got viewer for %s\n", name); } else { hemp_debug("installed view #%d\n", id); viewer->view[id] = view; } return HEMP_TRUE; }
void hemp_viewer_resize( HempViewer viewer, HempU16 min_size ) { hemp_debug_call("hemp_viewer_resize(%s, %d)\n", viewer->name, min_size); HempU16 old_size = viewer->size; HempU16 new_size = old_size; HempMemory buffer; HempU16 size; if (! new_size) new_size = HEMP_VIEW_SIZE; while (min_size >= new_size) { new_size = new_size << 1; } size = new_size * sizeof(hemp_view_f); buffer = hemp_mem_alloc(size); if (! buffer) hemp_mem_fail("viewer view buffer"); memset(buffer, 0, size); hemp_debug_mem("allocated and cleared %d bytes for %d views\n", size, new_size); if (old_size) { size = old_size * sizeof(hemp_view_f); hemp_mem_copy(viewer->view, buffer, size); hemp_debug_mem("copied %d bytes from previous %d views\n", size, old_size); hemp_mem_free(viewer->view); } viewer->view = buffer; viewer->size = new_size; }
HempModule hemp_use_module( Hemp hemp, HempString type, HempString name ) { hemp_debug_call("hemp_use_module(%s => %s)\n", type, name); HempValue path = hemp_config_get(hemp, HEMP_CONFIG_MODPATH); HempString string; if (hemp_is_defined(path)) { string = hemp_to_string(path, hemp->context); // hemp_debug_msg("already got %s: %s\n", HEMP_CONFIG_MODPATH, string); } else { HempValue dir = hemp_config_get(hemp, HEMP_CONFIG_DIR); HempValue mod = hemp_config_get(hemp, HEMP_CONFIG_MODDIR); HempString dstr = hemp_to_string(dir, hemp->context); HempString mstr = hemp_to_string(mod, hemp->context); string = hemp_uri_path_join(dstr, mstr, 1); // hemp_debug_msg("constructed %s: %s\n", HEMP_CONFIG_MODPATH, string); /* ugly work-around so we can get the context to manage memory */ HempText text = hemp_context_tmp_text_size(hemp->context, strlen(string) + 1); hemp_text_append_string(text, string); hemp_mem_free(string); string = text->string; // hemp_config_set(hemp, HEMP_CONFIG_MODPATH, hemp_text_val(text)); } // TODO: need a way to save dotted path (hemp.module_path) back into config /* quick hack to get something working */ HempString modpath = getenv("HEMP_MODULE_PATH"); if (! modpath || ! *modpath) { modpath = string; // hemp_debug_msg("No HEMP_MODULE_PATH environment variable set\n"); // return HEMP_FALSE; } /* TODO: sort this mess out */ HempString tpath = hemp_uri_path_join(modpath, type, 1); HempString mpath = hemp_uri_path_join(tpath, name, 1); HempText mtext = hemp_text_from_string(mpath); hemp_text_append_string(mtext, HEMP_MODULE_EXT); hemp_mem_free(mpath); hemp_mem_free(tpath); // hemp_debug_msg("constructed module path: %s\n", mtext->string); HempModule module = hemp_global_module(hemp->global, mtext->string); if (module->binder) { module->binder(module, hemp); } else if (module->error) { hemp_fatal(module->error); } else { /* should never happen - famous last word */ hemp_fatal("No binder function for %s module", name); } hemp_text_free(mtext); return module; }