From 1d295d11e5857442fe3a5dbcd62dca7c5553fb65 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sat, 29 Nov 2025 18:34:37 -0600 Subject: [PATCH] modifications to importing --- cell2.md | 7 ++ scripts/cellfs.cm | 2 - scripts/compile.ce | 11 +-- scripts/engine.cm | 166 +++++++++++++++++++++------------------------ 4 files changed, 90 insertions(+), 96 deletions(-) diff --git a/cell2.md b/cell2.md index 77538bd7..fab1c4c6 100644 --- a/cell2.md +++ b/cell2.md @@ -19,11 +19,18 @@ prosperon/ prosperon/sprite.cm prosperon/render.cm prosperon/_help.cm +prosperon/render.c prosperon/ui/ prosperon/ui/button.cm sprite.cm can use(render); but an outside package must use(prosperon/render). sprite can use(help), but an outside package cannot use(prosperon/help). +A file like render.c above will be compiled into a dynamic library for the target platform (ie, on macos a .dylib), named the name of the package, 'prosperon.dylib'. For a local package, it will be local.dylib. + +In the case above, the js_prosperon_render_use function will be found in the prosperon.dylib, and the result of that will be passed to render.cm as 'this', allowing for trivial extension. + +If a C function OR a .cm file is found for a particular import, searching stops, preventing, for example, accidentally applying a .cm file from a local find to a package that has one which is similarly named. + ### Importing packages Each package has a list of packages it depends on. They can use their own naming convention for them. Packages are imported from URLs, so, gitea.pockle.world/john/prosperon imports 'prosperon'; but, when importing, you can say, 'renderer = gitea.pockle.world/john/prosperon', and that means you can use(renderer/sprite), etc. diff --git a/scripts/cellfs.cm b/scripts/cellfs.cm index cec5e8aa..bc1bf2a8 100644 --- a/scripts/cellfs.cm +++ b/scripts/cellfs.cm @@ -187,8 +187,6 @@ function mount(source, name) { } mounts.push(mount_info) - - log.console(`Mounted ${source} ${name ? 'as @' + name : ''}`) } // Unmount diff --git a/scripts/compile.ce b/scripts/compile.ce index 18558f33..996ca037 100644 --- a/scripts/compile.ce +++ b/scripts/compile.ce @@ -2,8 +2,6 @@ var os = use('os') var io = use('cellfs') -log.console(json.encode(cell.config)) - var project_name = cell.config.project.name if (!project_name) { @@ -29,7 +27,7 @@ for (var i = 0; i < files.length; i++) { var safe_path = path_no_ext.replace(/\//g, '_').replace(/\\/g, '_') if (safe_path.startsWith('._')) safe_path = safe_path.substring(2) - var use_name = 'js_' + project_name + '_' + safe_path + '_use' + var use_name = 'js_local_' + safe_path + '_use' var obj_file = '.cell/build/' + file + '.o' var obj_dir = io.realdir(obj_file) @@ -69,7 +67,12 @@ if (os.platform() == 'macOS') { lib_ext = '.dll' } -var lib_name = project_name + lib_ext +// Ensure .cell/local exists +if (!io.exists('.cell/local')) { + io.mkdir('.cell/local') +} + +var lib_name = '.cell/local/local' + lib_ext log.console("Linking " + lib_name) var link_cmd = 'cc ' + link_flags + ' ' + objects.join(' ') + ' -lcell -o ' + lib_name diff --git a/scripts/engine.cm b/scripts/engine.cm index b96e7cc8..4d476b1f 100644 --- a/scripts/engine.cm +++ b/scripts/engine.cm @@ -8,11 +8,11 @@ var hidden = cell.hidden var os = hidden.os; cell.os = null - var dylib_ext + switch(os.platform()) { case 'Windows': dylib_ext = '.dll'; break; - case 'Darwin': dylib_ext = '.dylib'; break; + case 'macOS': dylib_ext = '.dylib'; break; case 'Linux': dylib_ext = '.so'; break; } @@ -204,34 +204,39 @@ function get_package_from_path(path) { return null } -// Config is loaded later, but we need to access it in resolve_module_path -// This will be set after shop.load_config() is called var config = null -// Unified path resolution function -// Unified path resolution function -function resolve_path(requested, pkg_context, ext) { - +// Scope definitions +var SCOPE_LOCAL = 0 +var SCOPE_DEPENDENCY = 1 +var SCOPE_CORE = 2 + +function resolve_path(requested, pkg_context, ext) { if (requested.endsWith(ext)) ext = '' var dependencies = (config && config.dependencies) ? config.dependencies : {} // Helper to check file existence and return result object - function check(path, pkg, isCore) { + function check(path, pkg, isCore, scope) { if (isCore) { try { var blob = core_qop.read(path) if (blob) { - // log.console("check: found in core: " + path) - return { path: path, package_name: null, isCore: true } + return { path: path, package_name: null, isCore: true, scope: scope } } return null } catch (e) { return null } } + + // Check for private files if accessing from a different package + if (pkg && current_package && pkg != current_package) { + var filename = path.substring(path.lastIndexOf('/') + 1) + if (filename.startsWith('_')) return null + } + if (fd.is_file(path)) { - // log.console("check: found file: " + path) - return { path: path, package_name: pkg, isCore: false } + return { path: path, package_name: pkg, isCore: false, scope: scope } } return null } @@ -239,20 +244,20 @@ function resolve_path(requested, pkg_context, ext) { // Step 1: current package (Local) if (pkg_context) { var pkg_path = '.cell/modules/' + pkg_context + '/' + requested + ext - var res = check(pkg_path, pkg_context, false) + var res = check(pkg_path, pkg_context, false, SCOPE_LOCAL) if (res) return res // Check if package is locally replaced if (config && config.replace && config.replace[pkg_context]) { var replace_path = config.replace[pkg_context] var full_path = replace_path + '/' + requested + ext - res = check(full_path, pkg_context, false) + res = check(full_path, pkg_context, false, SCOPE_LOCAL) if (res) return res } } else { // Top-level local var project_path = requested + ext - var res = check(project_path, null, false) + var res = check(project_path, null, false, SCOPE_LOCAL) if (res) return res } @@ -266,17 +271,17 @@ function resolve_path(requested, pkg_context, ext) { if (config && config.replace && config.replace[pkg_alias]) { var replace_path = config.replace[pkg_alias] var full_path = replace_path + '/' + (sub_path || pkg_alias) + ext - var res = check(full_path, pkg_alias, false) + var res = check(full_path, pkg_alias, false, SCOPE_DEPENDENCY) if (res) return res } else if (dependencies[pkg_alias]) { var dep_path = '.cell/modules/' + pkg_alias + '/' + sub_path + ext - var res = check(dep_path, pkg_alias, false) + var res = check(dep_path, pkg_alias, false, SCOPE_DEPENDENCY) if (res) return res } // Also check if it's just a module in .cell/modules even if not in dependencies (implicit) var implicit_path = '.cell/modules/' + requested + ext - var res = check(implicit_path, pkg_alias, false) + var res = check(implicit_path, pkg_alias, false, SCOPE_DEPENDENCY) if (res) return res } else { @@ -284,27 +289,26 @@ function resolve_path(requested, pkg_context, ext) { if (config && config.replace && config.replace[requested]) { var replace_path = config.replace[requested] var full_path = replace_path + '/' + requested + ext - var res = check(full_path, requested, false) + var res = check(full_path, requested, false, SCOPE_DEPENDENCY) if (res) return res } // Check dependencies for simple names for (var alias in dependencies) { if (alias == requested) { var dep_simple = '.cell/modules/' + alias + '/' + requested + ext - var res = check(dep_simple, alias, false) + var res = check(dep_simple, alias, false, SCOPE_DEPENDENCY) if (res) return res } } // Implicit check var implicit_path = '.cell/modules/' + requested + '/' + requested + ext - var res = check(implicit_path, requested, false) + var res = check(implicit_path, requested, false, SCOPE_DEPENDENCY) if (res) return res } // Step 3: core - var core_res = check(requested + ext, null, true) - if (core_res) log.console(`resolve_path: found core ${requested}`) + var core_res = check(requested + ext, null, true, SCOPE_CORE) return core_res } @@ -329,7 +333,6 @@ function get_compiled_path(resolved) { } var open_dl = {} - function get_c_symbol(requested, pkg_context) { // Construct symbol name: js_x_y_z_use var symname = `js_${requested.replace(/\//g, '_')}_use` @@ -348,9 +351,15 @@ function get_c_symbol(requested, pkg_context) { } if (dl) { try { - var sym = os.dylib_symbol(dl, symname) - if (sym) return sym - } catch(e) {} + // For local symbols, use js_local__use + var local_symname = `js_local_${requested.replace(/\//g, '_')}_use` + var sym = os.dylib_symbol(dl, local_symname) + if (sym) { + return { symbol: sym, scope: SCOPE_LOCAL } + } else { + } + } catch(e) { + } } } } @@ -375,65 +384,62 @@ function get_c_symbol(requested, pkg_context) { if (dl) { try { var sym = os.dylib_symbol(dl, symname) - if (sym) return sym + if (sym) return { symbol: sym, scope: SCOPE_DEPENDENCY } } catch(e) {} } } } + // 3. Check Core (Internal) + var internal_sym = load_internal(symname) + if (internal_sym) return { symbol: internal_sym, scope: SCOPE_CORE } + return null } +function get_module(name, pkg_context) { + return resolve_path(name, pkg_context, MOD_EXT) +} + +function get_actor_script(name, pkg_context) { + return resolve_path(name, pkg_context, ACTOR_EXT) +} + globalThis.use = function use(file, ...args) { var requested = file - log.console(`use: ${file}`) - // 1. Check Local - // Check for C symbol locally + // Find C symbol + var c_res = get_c_symbol(requested, current_package) + + // Find Module + var mod_res = get_module(requested, current_package) + var c_mod = null - if (!current_package) { - c_mod = get_c_symbol(requested, null) - } - var resolved = null - // Check for local file - if (!current_package) { - resolved = resolve_path(requested, null, MOD_EXT) - // If we found a core module but we were looking for local, ignore it for now - if (resolved && resolved.isCore) resolved = null - } - - // If we found something locally (C or Script), stop looking elsewhere - if (c_mod || resolved) { - // Proceed with local - } else { - // 2. Check Modules - // Check for C symbol in modules - // We need to guess the package name if not in a package context - var pkg_guess = requested.split('/')[0] - c_mod = get_c_symbol(requested, pkg_guess) - - if (!c_mod) { - // Check for module file - resolved = resolve_path(requested, null, MOD_EXT) // resolve_path handles module lookup if we pass null context but path has / - if (resolved && resolved.isCore) resolved = null + // Decision logic + if (c_res && mod_res) { + if (c_res.scope < mod_res.scope) { + // C symbol is more specific + c_mod = c_res.symbol + resolved = null + } else if (mod_res.scope < c_res.scope) { + // Module is more specific + c_mod = null + resolved = mod_res + } else { + // Same scope - use both (C symbol as context) + c_mod = c_res.symbol + resolved = mod_res } - } - - // 3. Check Core - if (!c_mod && !resolved) { + } else if (c_res) { + c_mod = c_res.symbol + } else if (mod_res) { + resolved = mod_res + } else { + // Try embed as fallback for core var embed_mod = use_embed(requested) if (embed_mod) c_mod = embed_mod - - var res = resolve_path(requested, null, MOD_EXT) - if (res && res.isCore) resolved = res - } - - // If still nothing - if (!c_mod && !resolved) { - // Try load_internal as last resort for core C - c_mod = load_internal(`js_${requested}_use`) } if (!c_mod && !resolved) @@ -452,14 +458,12 @@ globalThis.use = function use(file, ...args) { var context = {} if (c_mod) { context = c_mod - log.console("use: using c_mod as context") } // If we have a script, run it var ret = c_mod if (resolved) { - log.console("use: running script " + resolved.path) var path = resolved.path var isCore = resolved.isCore var module_package = resolved.package_name @@ -523,7 +527,6 @@ globalThis.use = function use(file, ...args) { } ret = fn.call(context, args, $_) - log.console("use: script returned " + (typeof ret)) current_package = prev_package loadingStack.pop() @@ -541,12 +544,10 @@ globalThis.use = function use(file, ...args) { } globalThis.json = use('json') -log.console(json.encode(cell)) var time = use('time') var st_now = time.number() var shop = use('shop') -log.console(`use shop in ${time.number() - st_now} seconds`) config = shop.load_config() var default_config = { ar_timer: 60, @@ -565,8 +566,6 @@ cell.config = config ENETSERVICE = config.system.net_service REPLYTIMEOUT = config.system.reply_timeout -log.console(`config loaded in ${time.number()-st_now} seconds`) - globalThis.text = use('text') // Load actor-specific configuration @@ -609,8 +608,6 @@ function deepFreeze(object) { return Object.freeze(object); } -log.console(`stone initialized in ${time.number()-st_now} seconds`) - globalThis.stone = deepFreeze stone.p = function(object) { @@ -997,8 +994,6 @@ load_actor_config(cell.args.program) actor_mod.register_actor(cell.id, turn, cell.args.main, config.system.ar_timer) -log.console(`actor registered in ${time.number()-st_now} seconds`) - if (config.system.actor_memory) js.mem_limit(config.system.actor_memory) @@ -1123,7 +1118,6 @@ function enet_check() // enet_check(); var init_end = time.number() -log.console(`initialization completed in ${init_end-st_now} seconds`) var load_program_start = time.number() @@ -1183,10 +1177,6 @@ if (useCompiled) { startfn = js.eval_compile(fn) } -log.console(`program compiled in ${time.number()-load_program_start} seconds`) - -var exec_start = time.number() - $_.clock(_ => { var val = startfn($_, cell.args.arg); @@ -1194,8 +1184,4 @@ $_.clock(_ => { throw new Error('Program must not return anything'); }) -log.console(`program queued in ${time.number()-exec_start} seconds`) - -log.console(`program executed in ${time.number()-st_now} seconds`) - })() \ No newline at end of file