reduce shop

This commit is contained in:
2025-12-08 19:50:09 -06:00
parent 38d6b4d4e8
commit 5c5427fdd9
9 changed files with 229 additions and 297 deletions

View File

@@ -35,6 +35,7 @@ all source for every single part of a cell program are located in the cell shop.
the cell shop looks like this:
.cell
shop.toml <---- shop configuration
packages
gitea.pockle.world/john/cell <--- this is the root cell
gitea.pockle.world/john/prosperon
@@ -61,4 +62,36 @@ When a module <name/mod> is requested, from a within package <a> ..
1) cell looks within package <a> for a folder <name> and loads <name/mod>, if present
2) cell looks for a package <name> with a top level <mod>
3) cell looks in the core for <name/mod>
3) cell looks in the core for <name/mod>
The core can be set and have something else linked into it, if you want to break your cell build
## cell build
cell build compiles all c into the appropriate binaries. All object files are stored in the .cell/cache
there are two ways to build a cell program: as a shared library, or as a static binary.
Cell script files are simply compiled into built objects
Then, all C files in the package are compiled.
If you have a file like fd.c and fd_playdate.c, that is a signal to cell to compile fd.c usually, but then for the playdate target, compile fd_playdate.c instead.
files name "main.c" are not compiled.
each cell.toml in a package
### shared library
this is more suitable for development. firstly, the cell core must build a shared library for the platform.
Then, each package compiles, linking to the cell core shared library. Modules are written to include the cell core headers.
Shared libraries are stored
### bootstrapping cell
after the cell shared libraries are all compiled, the main.c of the cell core is compiled against the cell core shared library, creating a thin cell runner. However, even on subsequent updates to cell, this runner is not updated; only for bootstrapping.
### static binary
For static binaries, rather than going through and compiling each dynamic library for a package, a static binary is created for a particular package, based on its dependencies. All C symbols, plus the main.c runner from the cell core, are packaged into one binary. It works just like the basic cell program.
However, you can also specify an entry point for this binary, for example, a particular actor. When the binary is run, that particular actor runs.

View File

@@ -9,6 +9,8 @@ cell.os = null
var dylib_ext
cell.id ??= "newguy"
switch(os.platform()) {
case 'Windows': dylib_ext = '.dll'; break;
case 'macOS': dylib_ext = '.dylib'; break;
@@ -54,20 +56,16 @@ function use_core(path) {
var cache_path = `2::${path}`;
if (use_cache[cache_path])
return use_cache[cache_path];
var sym = use_embed(path)
var sym = use_embed(path.replace('/','_'))
// Core scripts are now in .cell/core/scripts
var file_path = core_path + '/scripts/' + path + MOD_EXT
// Fallback check for root (optional, for backward compat if needed, but not strictly necessary if we are consistent)
if (!fd.is_file(file_path)) {
file_path = core_path + '/' + path + MOD_EXT
}
var file_path = core_path + '/' + path + MOD_EXT
if (fd.is_file(file_path)) {
var script_blob = fd.slurp(file_path)
var script = utf8.decode(script_blob)
var mod = `(function setup_${path}_module($_){${script}})`
var mod = `(function setup_module($_){${script}})`
var fn = js.eval(path, mod)
var result = fn.call(sym);
use_cache[cache_path] = result;
@@ -114,7 +112,7 @@ stone.p = function(object)
var actor_mod = use('actor')
var wota = use('wota')
var nota = use('nota')
globalThis.text = use('text')
globalThis.text = use('internal/text')
var ENETSERVICE = 0.1
var REPLYTIMEOUT = 60 // seconds before replies are ignored
@@ -231,7 +229,6 @@ function get_package_from_path(path) {
globalThis.json = use('json')
var time = use('time')
var st_now = time.number()
var default_config = {
ar_timer: 60,
@@ -653,16 +650,18 @@ if (!program) {
// Find the package containing the program
// The program path is resolved relative to current directory
var package_dir = shop.set_current_package(program)
if (package_dir) {
// Reload config from the package
config = shop.load_config()
if (config) {
config.system = config.system || {}
config.system.__proto__ = default_config
cell.config = config
}
}
// Find the package containing the program
// The program path is resolved relative to current directory
// var package_dir = shop.set_current_package(program)
// if (package_dir) {
// // Reload config from the package
// config = shop.load_config()
// if (config) {
// config.system = config.system || {}
// config.system.__proto__ = default_config
// cell.config = config
// }
// }
function handle_actor_disconnect(id) {
var greeter = greeters[id]

View File

@@ -298,7 +298,7 @@ static const JSCFunctionListEntry js_text_funcs[] = {
MIST_FUNC_DEF(text, base64url_to_blob, 1),
};
JSValue js_text_use(JSContext *js)
JSValue js_internal_text_use(JSContext *js)
{
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_text_funcs, countof(js_text_funcs));

View File

@@ -52,34 +52,33 @@ src += [ # core
src += ['scheduler.c']
scripts = [
'nota.c',
'js.c',
'internal/nota.c',
'debug/js.c',
'qop.c',
'wildstar.c',
'fit.c',
'crypto.c',
'text.c',
'internal/text.c',
'utf8.c',
'kim.c',
'internal/kim.c',
'time.c',
'nota.c',
'debug.c',
'os.c',
'internal/nota.c',
'debug/debug.c',
'internal/os.c',
'fd.c',
'http.c',
'enet.c',
'net/http.c',
'net/enet.c',
'wildstar.c',
'miniz.c',
'json.c'
'archive/miniz.c',
'internal/json.c'
]
foreach file: scripts
full_path = join_paths('scripts', file)
sources += files(full_path)
sources += files(file)
endforeach
srceng = 'source'
includes = [srceng]
includes = [srceng, 'internal', 'debug', 'net', 'archive']
foreach file : src
full_path = join_paths(srceng, file)
@@ -99,7 +98,6 @@ else
link += '-Wl,-export_dynamic'
endif
cell_so = shared_library(
'cell_runtime',
sources,
@@ -108,14 +106,6 @@ cell_so = shared_library(
install : true,
)
# Create core.zip from scripts folder
qop_target = custom_target('core.qop',
output: 'core.qop',
command: ['sh', '-c', ' qopconv -d ' + meson.project_source_root() / 'scripts . core.qop'],
build_by_default: true,
build_always_stale: true
)
# Determine RPATH based on OS
# MacOS uses @loader_path, Linux uses $ORIGIN
# We include both the current directory (for build) and ../lib (for install)
@@ -127,28 +117,14 @@ elif host_machine.system() == 'linux'
endif
# Create main executable linked against the cell library
cell_exe = executable('cell_exe',
cell_exe = executable('cell',
'source/main.c',
dependencies: deps,
include_directories: includers,
link_with: cell_so,
link_args: link,
build_rpath: ':'.join(rpath_dirs),
install: false
)
# Create final cell executable by appending core.zip to cell_exe
cell = custom_target('cell',
input: [cell_exe, qop_target],
output: 'cell' + exe_ext,
command: [
'sh', '-c',
'cp "$1" "$3" && cat "$2" >> "$3" && chmod +x "$3"',
'cell-cat', '@INPUT0@', '@INPUT1@', '@OUTPUT@'
],
build_by_default: true,
install: true,
install_dir: get_option('bindir')
install: true
)
# Install headers for building dynamic libraries using Cell

382
shop.cm
View File

@@ -10,13 +10,13 @@ var utf8 = use('utf8')
var blob = use('blob')
var build_utils = use('build')
var core = "gitea.pockle.world/john/cell"
function content_hash(content)
{
return text(crypto.blake2(utf8.encode(content)), 'h')
}
log.console(content_hash("hello"))
// a package string is what is used to import a module, like prosperon/sprite
// in prosperon/sprite, sprite is the module, and prosperon is the package (usually, an alias)
// a canonical package name relates prosperon to its source, like gitea.pockle.world/john/prosperon
@@ -27,9 +27,6 @@ var Shop = {}
// Located at ~/.cell on the user's machine
var global_shop_path = null
// Current package context - the package we're running from (resolved from program path)
var current_package_path = null
var SCOPE_LOCAL = 0
var SCOPE_PACKAGE = 1
var SCOPE_CORE = 2
@@ -165,21 +162,7 @@ function update_local_lock(abs_path) {
Shop.ensure_package_link = ensure_package_link
// Set the current package context from a program path
Shop.set_current_package = function(program_path) {
current_package_path = Shop.find_package_dir(program_path)
if (current_package_path && current_package_path.startsWith('/')) {
// It's a local package, ensure it is linked in the shop
ensure_package_link(current_package_path)
}
return current_package_path
}
// Get the current package path
Shop.get_current_package = function() {
return current_package_path
}
Shop.set_os = function(o, $guy)
{
@@ -203,9 +186,6 @@ function get_config_path(package_path) {
if (package_path) {
return package_path + '/cell.toml'
}
if (current_package_path) {
return current_package_path + '/cell.toml'
}
// Fallback to current directory
return 'cell.toml'
}
@@ -351,6 +331,10 @@ function get_path_in_package(path, ctx)
return canon_pkg + "/" + mod_name
}
// Given a path like 'prosperon/sprite', extract the package alias ('prosperon')
// and resolve it to its canonical path using the dependencies in ctx's config.
// Returns the canonical package path (e.g., 'gitea.pockle.world/john/prosperon')
// or null if the path has no package prefix or the package is not found.
function get_normalized_package(path, ctx)
{
var pkg = get_import_package(path)
@@ -773,35 +757,13 @@ Shop.check_cache = function(pkg) {
var open_dls = {}
// for script forms, path is the canonical path of the module
var script_forms = []
// Construct a descriptive compile name with extension preserved.
// Formats:
// core:<module path>
// <package>:<module path> (package is the full canonical package name)
// local:<module path>
// package:<module path> (fallback when pkg isn't provided but path is under modules)
function make_compile_name(path, rel_path, pkg, scope) {
if (scope == SCOPE_CORE) return 'core:' + rel_path
if (pkg) return pkg + ':' + rel_path
var modules_dir = get_modules_dir()
if (path && path.startsWith(modules_dir + '/')) return 'package:' + rel_path
return 'local:' + rel_path
}
script_forms['.cm'] = function(path, script, pkg) {
var script_form = function(path, script, pkg) {
var pkg_arg = pkg ? `'${pkg}'` : 'null'
var relative_use_fn = `def use = function(path) { return globalThis.use(path, ${pkg_arg});}`
var fn = `(function setup_module($_){ ${relative_use_fn}; ${script}})`
return fn
}
script_forms['.ce'] = function(path, script, pkg) {
var pkg_arg = pkg ? `'${pkg}'` : 'null'
var relative_use_fn = `def use = function(path) { return globalThis.use(path, ${pkg_arg});}`
return `(function start($_, arg) { ${relative_use_fn}; var args = arg; ${script} ; })`
}
// Get flags from config
function get_flags(config, platform, key) {
var flags = ''
@@ -817,170 +779,108 @@ function get_flags(config, platform, key) {
Shop.get_flags = get_flags
function get_build_dir(pkg) {
if (!pkg) pkg = current_package_path
if (!pkg) return get_global_build_dir() + '/local' // Fallback for non-package scripts
// If pkg is absolute path, mirror it
if (pkg.startsWith('/')) {
// Accio folder should be .cell/packages/Users/...
// But build should be .cell/build/packages/Users/...
return get_global_build_dir() + '/packages' + pkg
}
// Otherwise it's a relative package path (from packages dir)
return get_global_build_dir() + '/packages/' + pkg
}
Shop.get_build_dir = get_build_dir
Shop.get_global_build_dir = get_global_build_dir
function get_rel_path(path, pkg) {
if (!pkg) {
// For local files, strip the current package path prefix if present
if (current_package_path && path.startsWith(current_package_path + '/')) {
return path.substring(current_package_path.length + 1)
}
return path
}
var prefix
if (pkg.startsWith('/')) {
prefix = pkg + '/'
} else {
prefix = get_modules_dir() + '/' + pkg + '/'
}
if (path.startsWith(prefix)) {
return path.substring(prefix.length)
}
return path
}
function resolve_mod_fn(path, pkg)
{
// Resolve module function
function resolve_mod_fn(path, pkg) {
if (!fd.is_file(path)) throw new Error(`path ${path} is not a file`)
var rel_path = get_rel_path(path, pkg)
// Determine build directory based on context
var build_dir
if (pkg) {
build_dir = get_build_dir(pkg)
} else if (current_package_path) {
// Local file in current package - use package path (strip leading /)
var pkg_id = current_package_path.substring(1) // Remove leading /
build_dir = get_global_build_dir() + '/' + pkg_id
} else {
build_dir = get_build_dir('local')
}
var cache_path = build_dir + '/' + rel_path + '.o'
if (fd.is_file(cache_path) && fd.stat(path).mtime <= fd.stat(cache_path).mtime) {
var obj = fd.slurp(cache_path)
var content = fd.slurp(path)
var hash = content_hash(content)
var hash_path = get_global_build_dir() + '/' + hash
if (fd.is_file(hash_path)) {
var obj = fd.slurp(hash_path)
var fn = js.compile_unblob(obj)
return js.eval_compile(fn)
}
var ext = path.substring(path.lastIndexOf('.'))
var script_form = script_forms[ext]
if (!script_form) throw new Error(`No script form for extension ${ext}`)
var compile_name = make_compile_name(path, rel_path, pkg, pkg ? SCOPE_PACKAGE : SCOPE_LOCAL)
var script = script_form(path, text(fd.slurp(path)), pkg)
var form = script_form
// We don't really use pkg scope for compilation anymore since it's just hash based cache
// But we need to pass a package context for the 'use' function inside the module
var script = form(path, text(content), pkg);
// Compile name is just for debug/stack traces
var compile_name = pkg ? pkg + ':' + path : 'local:' + path
var fn = js.compile(compile_name, script)
ensure_dir(cache_path.substring(0, cache_path.lastIndexOf('/')))
fd.slurpwrite(cache_path, js.compile_blob(fn))
// Ensure build dir exists
ensure_dir(get_global_build_dir())
fd.slurpwrite(hash_path, js.compile_blob(fn))
return js.eval_compile(fn)
}
// Resolve and cache a core module
function resolve_core_mod_fn(core_path, rel_path) {
var build_dir = get_global_build_dir() + '/core'
var cache_path = build_dir + '/' + rel_path + '.o'
if (fd.is_file(cache_path) && fd.stat(core_path).mtime <= fd.stat(cache_path).mtime) {
var obj = fd.slurp(cache_path)
var fn = js.compile_unblob(obj)
return js.eval_compile(fn)
}
var ext = core_path.substring(core_path.lastIndexOf('.'))
var form = script_forms[ext]
if (!form) throw new Error(`No script form for extension ${ext}`)
var compile_name = make_compile_name(core_path, rel_path, null, SCOPE_CORE)
var script = form(null, text(fd.slurp(core_path)))
var fn = js.compile(compile_name, script)
ensure_dir(cache_path.substring(0, cache_path.lastIndexOf('/')))
fd.slurpwrite(cache_path, js.compile_blob(fn))
return js.eval_compile(fn)
}
// resolve_core_mod_fn is no longer needed as core modules are just modules in a package (or local)
function resolve_locator(path, ext, ctx)
{
// In static_only mode, only look in the embedded pack
var static_only = cell.static_only
if (path.endsWith(ext)) ext = ''
// 1. Check local file (relative to current directory if no context, or relative to package 'ctx' if provided)
// If ctx is provided, it's a package alias or path.
var local_path
if (ctx) {
var mod_dir = get_modules_dir()
// Check if ctx is an absolute path (local package)
if (ctx.startsWith('/')) {
local_path = ctx + '/' + path + ext
} else {
local_path = mod_dir + '/' + ctx + '/' + path + ext
}
} else {
// No context, just check simple local path
local_path = path + ext
}
if (!static_only) {
// First, check if file exists in current package directory
if (current_package_path) {
var pkg_local_path = current_package_path + '/' + path + ext
if (fd.is_file(pkg_local_path)) {
var fn = resolve_mod_fn(pkg_local_path, null)
return {path: pkg_local_path, scope: SCOPE_LOCAL, symbol:fn}
}
}
// Check CWD for local file
var local_path
if (ctx)
local_path = get_modules_dir() + '/' + ctx + '/' + path + ext
else
local_path = path + ext
if (fd.is_file(local_path)) {
if (fd.is_file(local_path)) {
var fn = resolve_mod_fn(local_path, ctx)
return {path: local_path, scope: SCOPE_LOCAL, symbol:fn}
}
// Check installed packages
var canonical_pkg = get_normalized_package(path, ctx)
var pkg_path = get_path_in_package(path, ctx)
var mod_path = get_modules_dir() + '/' + pkg_path + ext
if (fd.is_file(mod_path)) {
var fn = resolve_mod_fn(mod_path, canonical_pkg)
return {path: mod_path, scope: SCOPE_PACKAGE, symbol:fn}
}
} else {
// Fallback: check if the path itself is a file (ignoring required extension)
// This allows running scripts like 'test.cm' even if engine asks for '.ce'
if (ext && path != local_path && fd.is_file(path)) {
var fn = resolve_mod_fn(path, ctx)
return {path: path, scope: SCOPE_LOCAL, symbol:fn}
}
}
// Check core directory for core modules
var core_dir = Shop.get_core_dir()
// For packages, try the full package path first in core
if (ctx) {
var pkg_rel = ctx + '/' + path + ext
var pkg_core_path = core_dir + '/' + pkg_rel
if (fd.is_file(pkg_core_path)) {
var fn = resolve_core_mod_fn(pkg_core_path, pkg_rel)
return {path: pkg_rel, scope: SCOPE_CORE, symbol:fn};
}
// 2. Check installed packages (if path suggests a package import)
// This handles imports like 'prosperon/sprite'
var canonical_pkg = get_normalized_package(path, ctx)
if (canonical_pkg) {
var pkg_path = get_path_in_package(path, ctx)
var mod_path = get_modules_dir() + '/' + pkg_path + ext
if (fd.is_file(mod_path)) {
var fn = resolve_mod_fn(mod_path, canonical_pkg)
return {path: mod_path, scope: SCOPE_PACKAGE, symbol:fn}
}
}
// Check core directory for the module
// Core scripts are now in .cell/core/scripts
// 3. Check core (as a fallback)
// "core" is now just another package, potentially.
// But if the user really wants to load "time", "js", etc, which are in core.
// We can try to resolve them in the core package.
// Ideally 'core' is defined in dependencies if needed, or we hardcode a fallback.
// Hardcoded fallback for now to match behavior:
var core_dir = Shop.get_core_dir()
var core_file_path = core_dir + '/scripts/' + path + ext
if (path == 'text') log.console("Checking core mod: " + core_file_path + " exists: " + fd.is_file(core_file_path))
var core_file_path = core_dir + '/' + path + ext
if (fd.is_file(core_file_path)) {
var fn = resolve_core_mod_fn(core_file_path, path + ext)
// Core is treated as a package now, essentially
var fn = resolve_mod_fn(core_file_path, 'core') // using 'core' string as package for now
return {path: path + ext, scope: SCOPE_CORE, symbol:fn};
}
return null;
}
function c_sym_path(path)
{
return path.replace(/\//g, '_').replace(/\\/g, '_').replace(/\./g, '_').replace(/-/g, '_')
@@ -989,14 +889,16 @@ function c_sym_path(path)
function resolve_c_symbol(path, package_context)
{
var static_only = cell.static_only
var local_path = package_context ? package_context : 'local'
var local_sym_base = c_sym_path(path)
var local
// Candidates for symbol names
function symbol_candidates(pkg_path, mod_sym) {
var variants = []
// if pkg_path is 'gitea.pockle.world/john/prosperon', we want:
// js_gitea_pockle_world_john_prosperon_mod_use
// and maybe with leading slash?
var paths = [pkg_path]
if (!pkg_path.startsWith('/')) paths.push('/' + pkg_path)
// if (!pkg_path.startsWith('/')) paths.push('/' + pkg_path) // unlikely to need slash variant for standard pkgs
for (var i = 0; i < paths.length; i++) {
var candidate = `js_${c_sym_path(paths[i])}_${mod_sym}_use`
if (variants.indexOf(candidate) < 0)
@@ -1004,37 +906,40 @@ function resolve_c_symbol(path, package_context)
}
return variants
}
if (!package_context) {
local = `js_local_${local_sym_base}_use`
} else {
local = null // handled via candidates below
}
// First check for statically linked/internal symbols
var local_candidates = package_context ? symbol_candidates(local_path, local_sym_base) : [local]
for (var li = 0; li < local_candidates.length; li++) {
var lc = local_candidates[li]
if (os.internal_exists(lc))
return {
symbol: function() { return os.load_internal(lc); },
scope: SCOPE_LOCAL,
path: lc
};
}
// In static_only mode, skip dynamic library lookups
// 1. Check internal symbols (statically linked)
// If we have a package context, we check package-prefixed symbols
// If not, we look for 'js_local_...' or 'js_path_use' directly?
if (package_context) {
// Check package internal symbols
var variants = symbol_candidates(package_context, local_sym_base)
for (var i = 0; i < variants.length; i++) {
if (os.internal_exists(variants[i])) {
return {
symbol: function() { return os.load_internal(variants[i]); },
scope: SCOPE_PACKAGE,
path: variants[i]
}
}
}
// In static_only mode, skip dynamic library lookups
if (!static_only) {
// Then try dynamic library
var build_dir = get_build_dir(package_context)
var local_dl_name = build_dir + '/libcellmod' + dylib_ext
// Use ./libcellmod for local?
var local_dl_name = './libcellmod' + dylib_ext
// Or check package context dir if it's a local package path?
if (package_context && package_context.startsWith('/')) {
local_dl_name = package_context + '/libcellmod' + dylib_ext
}
if (fd.is_file(local_dl_name)) {
if (!open_dls[local_dl_name])
open_dls[local_dl_name] = os.dylib_open(local_dl_name);
if (open_dls[local_dl_name]) {
var locals = package_context ? symbol_candidates(local_path, local_sym_base) : [local]
var locals = package_context ? symbol_candidates(package_context, local_sym_base) : [`js_local_${local_sym_base}_use`]
for (var i = 0; i < locals.length; i++) {
var candidate = locals[i]
if (os.dylib_has_symbol(open_dls[local_dl_name], candidate))
@@ -1047,8 +952,19 @@ function resolve_c_symbol(path, package_context)
}
}
}
} else {
// Local context
var local_sym = `js_local_${local_sym_base}_use`
if (os.internal_exists(local_sym)) {
return {
symbol: function() { return os.load_internal(local_sym); },
scope: SCOPE_LOCAL,
path: local_sym
}
}
}
// If 'path' has a package alias (e.g. 'prosperon/sprite'), try to resolve it
// 2. Check if valid package import (e.g. 'prosperon/sprite')
var pkg_alias = get_import_package(path)
if (pkg_alias) {
var canon_pkg = get_normalized_package(path, package_context)
@@ -1057,21 +973,20 @@ function resolve_c_symbol(path, package_context)
var mod_sym = mod_name.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_')
var sym_names = symbol_candidates(canon_pkg, mod_sym)
// First check internal/static symbols for package
for (var sii = 0; sii < sym_names.length; sii++) {
var sym_name = sym_names[sii]
if (os.internal_exists(sym_name))
return {
symbol: function() { return os.load_internal(sym_name) },
scope: SCOPE_PACKAGE,
package: canon_pkg,
path: sym_name
};
for (var i = 0; i < sym_names.length; i++) {
if (os.internal_exists(sym_names[i])) {
return {
symbol: function() { return os.load_internal(sym_names[i]); },
scope: SCOPE_PACKAGE,
package: canon_pkg,
path: sym_names[i]
}
}
}
// Then try dynamic library for package (skip in static_only mode)
if (!static_only) {
var pkg_build_dir = get_build_dir(canon_pkg)
// Check package dir for libcellmod
var pkg_build_dir = get_modules_dir() + '/' + canon_pkg
var dl_path = pkg_build_dir + '/libcellmod' + dylib_ext
if (fd.is_file(dl_path)) {
if (!open_dls[dl_path]) open_dls[dl_path] = os.dylib_open(dl_path)
@@ -1092,6 +1007,7 @@ function resolve_c_symbol(path, package_context)
}
}
// 3. Check Core/General fallback (js_path_use)
var core_sym = `js_${path.replace(/\//g, '_')}_use`;
if (os.internal_exists(core_sym))
return {
@@ -1150,14 +1066,20 @@ function execute_module(info)
var used
if (c_resolve.scope < mod_resolve.scope)
used = c_resolve.symbol(null, $_)
else if (mod_resolve.scope < c_resolve.scope)
used = mod_resolve.symbol.call(null, $_)
else
used = mod_resolve.symbol.call(c_resolve.symbol(), $_)
if (!used)
// If we have a script, it always takes precedence (containing the C symbol if available)
// This supports "Hybrid" modules where JS wraps C.
if (mod_resolve.scope < 900) {
var context = null
if (c_resolve.scope < 900) {
context = c_resolve.symbol(null, $_)
}
used = mod_resolve.symbol.call(context, $_)
} else if (c_resolve.scope < 900) {
// C only
used = c_resolve.symbol(null, $_)
} else {
throw new Error(`Module ${info.path} could not be found`)
} if (!used)
throw new Error(`Module ${json.encode(info)} returned null`)
return used
@@ -1172,10 +1094,6 @@ function get_module(path, package_context) {
return execute_module(info)
}
// first looks in local
// then in dependencies
// then in core
// package_context: optional package context to resolve relative paths within
Shop.use = function(path, package_context) {
var info = resolve_module_info(path, package_context)
if (!info)
@@ -1585,7 +1503,7 @@ Shop.remove_replacement = function(alias) {
// List all files in a package
Shop.list_files = function(pkg) {
var dir
if (!pkg) dir = current_package_path || '.'
if (!pkg) dir = '.'
else dir = get_modules_dir() + '/' + pkg
var files = []

View File

@@ -11,7 +11,7 @@
#include "cell.h"
#include "cell_internal.h"
#define ENGINE "scripts/engine.cm"
#define ENGINE "internal/engine.cm"
#define CELL_SHOP_DIR ".cell"
#define CELL_CORE_DIR "core"

View File

@@ -69,7 +69,7 @@ static const JSCFunctionListEntry js_time_funcs[] = {
};
JSValue
js_time_use(JSContext *ctx)
js_internal_time_use(JSContext *ctx)
{
JSValue obj = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, obj,
@@ -78,3 +78,9 @@ js_time_use(JSContext *ctx)
sizeof(js_time_funcs[0]));
return obj;
}
JSValue
js_time_use(JSContext *ctx)
{
return js_internal_time_use(ctx);
}