Skip to content

Commit c09d4bd

Browse files
committed
Add support for importing modules without extension, replace the module index name by file.
1 parent f22e47b commit c09d4bd

File tree

12 files changed

+259
-42
lines changed

12 files changed

+259
-42
lines changed

source/loader/include/loader/loader_naming.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ extern "C" {
2929

3030
#define LOADER_NAMING_PATH_SIZE 0x01FF
3131
#define LOADER_NAMING_NAME_SIZE 0xFF
32-
#define LOADER_NAMING_TAG_SIZE 0x12
32+
#define LOADER_NAMING_TAG_SIZE 0x40
3333

3434
typedef char loader_naming_path[LOADER_NAMING_PATH_SIZE];
3535
typedef char loader_naming_name[LOADER_NAMING_NAME_SIZE];

source/loader/include/loader/loader_path.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ LOADER_API size_t loader_path_get_fullname(const loader_naming_path path, loader
3737

3838
LOADER_API size_t loader_path_get_extension(const loader_naming_path path, loader_naming_tag extension);
3939

40+
LOADER_API size_t loader_path_get_module_name(const loader_naming_path path, loader_naming_name name, const loader_naming_tag extension);
41+
4042
LOADER_API size_t loader_path_get_path(const loader_naming_path path, size_t size, loader_naming_path absolute);
4143

4244
LOADER_API size_t loader_path_get_relative(const loader_naming_path base, const loader_naming_path path, loader_naming_path relative);

source/loader/source/loader_impl.c

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -608,24 +608,8 @@ int loader_impl_load_from_file(loader_impl impl, const loader_naming_path paths[
608608
return 1;
609609
}
610610

611-
/* TODO: Refactor loader_path_get_name from path 0 (for avoiding collisions of scripts): */
612-
/*
613-
int loader_impl_load_from_file_ex(loader_impl impl, const loader_naming_path paths[], size_t size, const char * name, size_t length, void ** handle_ptr)
614-
{
615-
...
616-
if (name == NULL)
617-
{
618-
loader_path_get_name(paths[0], module_name)
619-
}
620-
else
621-
{
622-
// TODO: Name must be a generated UUID to avoid collisions
623-
strncpy(module_name, name, length);
624-
}
625-
}
626-
*/
627-
628-
if (loader_path_get_name(paths[0], module_name) > 1 && loader_impl_get_handle(impl, module_name) != NULL)
611+
/* TODO: Refactor loader_path_get_fullname from path 0 (for avoiding collisions of scripts): */
612+
if (loader_path_get_fullname(paths[0], module_name) > 1 && loader_impl_get_handle(impl, module_name) != NULL)
629613
{
630614
log_write("metacall", LOG_LEVEL_ERROR, "Load from file handle failed, handle with name %s already loaded", module_name);
631615

source/loader/source/loader_path.c

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ size_t loader_path_get_name(const loader_naming_path path, loader_naming_name na
3434
size_t i, count, last;
3535

3636
for (i = 0, count = 0, last = 0; path[i] != '\0' &&
37-
i < LOADER_NAMING_PATH_SIZE /*&& count < LOADER_NAMING_NAME_SIZE*/; ++i)
37+
i < LOADER_NAMING_PATH_SIZE && count < LOADER_NAMING_NAME_SIZE; ++i)
3838
{
3939
name[count++] = path[i];
4040

@@ -44,17 +44,30 @@ size_t loader_path_get_name(const loader_naming_path path, loader_naming_name na
4444
}
4545
else if (path[i] == '.')
4646
{
47-
if (count > 0)
47+
if (i > 0 && path[i - 1] == '.')
4848
{
49-
last = count - 1;
49+
last = 0;
50+
count = 0;
5051
}
5152
else
5253
{
53-
last = 0;
54+
if (count > 0)
55+
{
56+
last = count - 1;
57+
}
58+
else
59+
{
60+
last = 0;
61+
}
5462
}
5563
}
5664
}
5765

66+
if (last == 0 && count > 1)
67+
{
68+
last = count;
69+
}
70+
5871
name[last] = '\0';
5972

6073
return last + 1;
@@ -65,7 +78,7 @@ size_t loader_path_get_fullname(const loader_naming_path path, loader_naming_nam
6578
size_t i, count;
6679

6780
for (i = 0, count = 0; path[i] != '\0' &&
68-
i < LOADER_NAMING_PATH_SIZE /*&& count < LOADER_NAMING_NAME_SIZE*/; ++i)
81+
i < LOADER_NAMING_PATH_SIZE && count < LOADER_NAMING_NAME_SIZE; ++i)
6982
{
7083
name[count++] = path[i];
7184

@@ -85,11 +98,11 @@ size_t loader_path_get_extension(const loader_naming_path path, loader_naming_ta
8598
size_t i, count;
8699

87100
for (i = 0, count = 0; path[i] != '\0' &&
88-
i < LOADER_NAMING_PATH_SIZE /*&& count < LOADER_NAMING_TAG_SIZE*/; ++i)
101+
i < LOADER_NAMING_PATH_SIZE; ++i)
89102
{
90103
extension[count++] = path[i];
91104

92-
if (path[i] == '.')
105+
if (LOADER_PATH_SEPARATOR(path[i]) || path[i] == '.' || count == LOADER_NAMING_TAG_SIZE)
93106
{
94107
count = 0;
95108
}
@@ -100,6 +113,23 @@ size_t loader_path_get_extension(const loader_naming_path path, loader_naming_ta
100113
return count + 1;
101114
}
102115

116+
size_t loader_path_get_module_name(const loader_naming_path path, loader_naming_name name, const loader_naming_tag extension)
117+
{
118+
loader_naming_tag name_extension;
119+
120+
size_t i, size = loader_path_get_extension(path, name_extension);
121+
122+
for (i = 0; i < size && extension[i] != '\0'; ++i)
123+
{
124+
if (name_extension[i] != extension[i])
125+
{
126+
return loader_path_get_fullname(path, name);
127+
}
128+
}
129+
130+
return loader_path_get_name(path, name);
131+
}
132+
103133
size_t loader_path_get_path(const loader_naming_path path, size_t size, loader_naming_path absolute)
104134
{
105135
size_t i, last, path_size = size > LOADER_NAMING_PATH_SIZE ? LOADER_NAMING_PATH_SIZE : size;

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ loader_handle py_loader_impl_load_from_file(loader_impl impl, const loader_namin
18211821
{
18221822
loader_naming_name module_name;
18231823

1824-
loader_path_get_name(paths[iterator], module_name);
1824+
loader_path_get_module_name(paths[iterator], module_name, "py");
18251825

18261826
py_handle->modules[iterator].name = PyUnicode_DecodeFSDefault(module_name);
18271827

source/loaders/rb_loader/source/rb_loader_impl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ loader_handle rb_loader_impl_load_from_file(loader_impl impl, const loader_namin
10831083

10841084
loader_naming_name module_name;
10851085

1086-
loader_path_get_name(paths[iterator], module_name);
1086+
loader_path_get_module_name(paths[iterator], module_name, "rb");
10871087

10881088
rb_module = rb_loader_impl_load_from_file_module(impl, paths[iterator], module_name);
10891089

source/ports/node_port/index.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,13 @@ const metacall_handle = (tag, name) => {
9797
return ctx.find(script => script.name === name);
9898
};
9999

100-
const metacall_require = (tag, name, id) => {
100+
const metacall_require = (tag, name) => {
101101
// TODO: Inspect only the handle instead of the whole metacall namespace
102102
/* return */ addon.metacall_load_from_file(tag, [ name ]);
103103

104+
104105
const inspect = metacall_inspect();
105-
const script = inspect[tag].find(script => script.name === id);
106+
const script = inspect[tag].find(s => s.name === name);
106107
const obj = {};
107108

108109
for (const func of script.scope.funcs) {
@@ -164,16 +165,15 @@ mod.prototype.require = function (name) {
164165
if (index !== -1) {
165166
/* If there is extension, load the module depending on the tag */
166167
const extension = name.substr(index + 1);
167-
const id = path.basename(name.substr(0, index));
168168
const tag = tags[extension];
169169

170170
if (tag && tag !== 'node') {
171171
/* Load with MetaCall if we found a tag and it is not NodeJS */
172-
return metacall_require(tag, name, id);
172+
return metacall_require(tag, name);
173173
}
174174
}
175175

176-
/* If there is no extension or the extension is not supported, load it with NodeJS require */
176+
/* If there is no extension or the extension is not supported or it is 'node', load it with NodeJS require */
177177
try {
178178
/* Cache the port */
179179
if (require.resolve(name) === path.resolve(__filename)) {
@@ -182,7 +182,22 @@ mod.prototype.require = function (name) {
182182
/* Call to real NodeJS require */
183183
return node_require.apply(this, [ name ]);
184184
} catch (e) {
185-
/* Print the exception and rethrow it */
185+
/* If it is not a NodeJS module, try to guess the runtime */
186+
const loaders = new Set(Object.values(tags));
187+
188+
/* Mock and node loaders are not included */
189+
loaders.delete('mock');
190+
loaders.delete('node');
191+
192+
for (let it = loaders.values(), tag = null; tag = it.next().value; ) {
193+
try {
194+
return metacall_require(tag, name);
195+
} catch (_) {
196+
/* Keep trying with the next loader */
197+
}
198+
}
199+
200+
/* It could not be loaded */
186201
console.log(e);
187202
throw e;
188203
}

source/ports/node_port/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

source/ports/node_port/test/index.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ describe('metacall', () => {
4646
it('metacall_load_from_file (py)', () => {
4747
assert.strictEqual(metacall_load_from_file('py', [ 'helloworld.py' ] ), undefined);
4848

49-
const script = metacall_handle('py', 'helloworld');
49+
const script = metacall_handle('py', 'helloworld.py');
5050
assert.notStrictEqual(script, undefined);
51-
assert.strictEqual(script.name, 'helloworld');
51+
assert.strictEqual(script.name, 'helloworld.py');
5252
});
5353
it('metacall_load_from_file (rb)', () => {
5454
assert.strictEqual(metacall_load_from_file('rb', [ 'ducktype.rb' ]), undefined);
5555

56-
const script = metacall_handle('rb', 'ducktype');
56+
const script = metacall_handle('rb', 'ducktype.rb');
5757
assert.notStrictEqual(script, undefined);
58-
assert.strictEqual(script.name, 'ducktype');
58+
assert.strictEqual(script.name, 'ducktype.rb');
5959
});
6060
it('metacall_load_from_memory (py)', () => {
6161
assert.strictEqual(metacall_load_from_memory('py', 'def py_memory():\n\treturn 4;\n'), undefined);
@@ -95,6 +95,18 @@ describe('metacall', () => {
9595
assert.deepStrictEqual(example.return_array(), [1, 2, 3]);
9696
assert.deepStrictEqual(example.return_same_array([1, 2, 3]), [1, 2, 3]);
9797
});
98+
it('require (py module)', () => {
99+
// This code loads directly a module without extension from Python
100+
const { loads } = require('json');
101+
assert.notStrictEqual(loads, undefined);
102+
assert.deepStrictEqual(loads('["foo", "bar"]'), ['foo', 'bar']);
103+
});
104+
it('require (py submodule)', () => {
105+
// This code loads directly a module without extension from Python
106+
const { py_encode_basestring_ascii } = require('json.encoder');
107+
assert.notStrictEqual(py_encode_basestring_ascii, undefined);
108+
assert.strictEqual(py_encode_basestring_ascii('asd'), '"asd"');
109+
});
98110
it('require (rb)', () => {
99111
const cache = require('cache.rb');
100112
assert.notStrictEqual(cache, undefined);

0 commit comments

Comments
 (0)